Remember me functionality is a mechanism that lets users log in automatically, even when they re-start their browser. In other words: after their session cookie is deleted by the browser (which is normally after closing the browser). This is implemented by setting up another cookie that will live in the browser’s database for a longer period (e.g. weeks). Spring out of the box offers two implementations of this feature. This tutorial presents two different approaches to cookie creation: hash-based token and persistent token. We will only look into the remember-me part of the Spring Security configuration, if you need more information look at basic setup.
Implemented by org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices, it creates a base64 encoded cookie that contains:
- username – you will be logged in as this username, if cookie is confirmed to be authentic.
- expiryTime – Spring will treat cookie as invalid after expiry time. The cookie is set to be valid for 2 weeks when created.
- hash – md5 hash of 2 values above, user’s password, and a key.
Hash is used to confirm that cookie is valid – e.g. no-one has tried to tweak the cookie manually. A key is a very important variable here – we set it in Spring’s configuration and it should be a unique, secret for our application. As nobody knows what key we have picked, no one will be able to generate valid hash. The above also means that:
- There is no extra information stored on the server side.
- If cookie is intercepted by an attacker, it can be used to log in as valid user.
- Username is exposed in cookie and can be read
- Cookie becomes invalid when user changes password.
The configuration itself is trivial, simply add one line with <remember-me> tag to security.xml (again, refer to the previous post for basics):
To test functionality, delete JSESSIONID cookie and refresh. Normally that would effectively result in a logging out but with our “remember me” cookie, new JSESSIONID is created straight away.
A better solution to remember me cookie is to use totally random string that will be stored as a cookie and has no meaningful data in itself. The disadvantage is that it requires storing some information on the server side. When token is presented from user’s browser, it is matched against a record in table with all tokens. Our Spring configuration will change only a bit.
We will also need a table “persistent_logins” to store tokens. For MySQL you can use following SQL.
As you can see there are actually two new pieces there: series and token. Both are random strings and both are passed back to user and stored in the cookie. The idea here is that token will be changed on every “remember me” login, so when a user comes with valid series but invalid token – the chances are that the cookie has been stolen and used for authentication! We could not prevent stealing the cookie but we can at least:
- warn user
- invalidate all tokens for current user
And this is exactly what Spring Security is doing.