Bozhidar Bozhanov

About Bozhidar Bozhanov

Senior Java developer, one of the top stackoverflow users, fluent with Java and Java technology stacks - Spring, JPA, JavaEE. Founder and creator of Computoser and Welshare. Worked on Ericsson projects, Bulgarian e-government projects and large-scale online recruitment platforms.

Login Tokens In Email Links

Your system is probably sending some emails. Sometimes these emails contain links to the public part of the site, sometimes they have links to the authentication-protected part. Either way, if the email is sent to registered users (as opposed to just subscribed emails) you should not make the user type in username and password. Even if it’s the public part of the site, the user may then want to do something that requires authentication with the content you display – e.g. add it to favourites. It’s a bit tricky with public content though, and you might not want to have it there, as users tend to forward “digest” or “best this week” emails, and then the recipients will be able to impersonate them, without even knowing.

Anyway, when users click on a link in an email sent by your system, they could be
 
logged in automatically. That’s the product requirement I think many systems should have, and it sounds pretty reasonable. But I’ve rarely seen in. Let’s assume you like it and you want to implement it in your system. How to do that, as there are certainly some security implications?

  1. For each email sent, generate a token. The token should be the HMAC of (the user’s email (or username, or id) concatenated with the token generation timestamp)
  2. Use an application-wide, configurable per-environment key for the HMAC. Also use a good hash algorithm, like SHA-256 (and not MD5)
  3. Append the token to each link in the email. You are probably using an email template, so just have ?emailLoginToken=${token} for each link. Also pass the email and the timestamp as parameters.
  4. Have a filter/interceptor that looks for that specific parameter name, and if it is found, invoke the authentication-by-token logic (described below)
  5. Redo the HMAC with the parameters passed (email and timestamp) and compare it to the token parameter
  6. Check if the token is still valid – you can have an expiration period and don’t allow tokens to be used after more than 2 weeks after generating them.
  7. If everything is OK (the token passed and the result of redoing the HMAC are the same), login the user (send a session cookie). But add a flag (in the session) that the login was via a token. Then do not allow changing password, email or any “sensitive” action without password confirmation. Use the same conditions as in your “remember me” login, if you have implemented that.
  8. Have all such links go through https

There’s another, slightly different scenario. Instead of using hmac and sending all the parameters, just generate the token as the hash of the email and timestamp and store it (and the timestamp) in the database, with foreign key to the users table. In this case, the authenticity confirmation comes from the fact, that it’s found in your database, rather than through verifying an HMAC. Then, when the token is presented as a parameter, simply look it up in the database. You should still pass the user’s email as parameter and compare the passed email parameter to the email of the user corresponding to the persisted token (to avoid guesses). On successful login you can delete the token. You may decide not to do this, and have a scheduled job that cleans up tokens older than X weeks. If you delete it immediately, it will be more secure. If you leave it, it will make it possible for the user to open the same mail again, and the login will still work. This approach lets you invalidate tokens on demand. For example if users decides to change their password or email, you can invalidate all their tokens.

It seems like a tough process, but it’s fairly easy to implement. The tough part is taking all the points into account and not compromising security. Note that security is an important aspect here. As pointed out on reddit, email may be insecure – when the user downloads emails via unsecured POP3 (with Outlook, Thunderbird, etc), an attacker may obtain the links and impersonate the user. That’s why you should restrict the actions the user can perform when logged in via a token. This may not matter that much, since most users either use webmail or secured POP3, or internal email server. But you should not do that for banking software, for example. Having tokens in links is probably less problematic than password reset links, though, which can also be intercepted the same way. But I’ll probably discuss that in a separate article.

One extra step you can take when addressing security is restrict the token authentication to the most often used IP addresses by the user. Overall, the above approach has more pros than security risks, so I believe any mainstream site should implement it (having in mind all the security implications).
 

Reference: Login Tokens In Email Links from our JCG partner Bozhidar Bozhanov at the Bozho’s tech blog blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


9 × = eighteen



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close