Brief description

Remember-me or persistent-login authentication refers to websites that can remember a user's identity between sessions. This is typically achieved by sending a cookie to the browser, with the cookie being detected during subsequent sessions and resulting in automatic login. Spring Security provides the necessary interceptors to perform these operations and has two specific implementations of remember-me. One uses hashing to maintain the security of cookie-based tokens, and the other uses a database or other persistent storage mechanism to store the generated tokens.

Note that both implementations require UserDetailsService. If you are using an authentication provider that does not use UserDetailsService (such as an LDAP provider), then it will not work unless there is also a UserDetailsService bean in the application context.

Simple approach using hash-based tokens

This approach uses hashing to successfully implement the useful remember-me strategy. Essentially, a cookie is sent to the browser after successful interactive authentication, and the cookie consists of the following elements:

base64(username + ":" + expirationTime + ":" +
md5Hex(username + ":" + expirationTime + ":" password + ":" + key))
username:          Which can determine the UserDetailsService
password:          Same as the one contained in the received UserDetails
expirationTime:    Date and time of expiration of the remember-me token, expressed in milliseconds
key:               Private key to prevent changes to the remember-me

Thus, the remember-me token is only valid for the specified period and provided that the username, password and key do not change. Notably, there is a potential security issue in this case, as the resulting remember-me token will be available for use by any user agent until the token expires. This is the same problem as with digest authentication. If the principal knows that the token has been intercepted, he can easily change his password and immediately revoke all issued remember-me tokens. If more advanced protection is required, the approach described in the next section should be used. Or remember-me services should not be used at all.

If you are familiar with the topics covered in the namespace configuration chapter, you can enable remember-me authentication by simply adding a <remember-me> element:

<http>
...
<remember-me key="myAppKey"/>
</http>

The specific UserDetailsService is usually selected automatically. If you have more than one in your application context, you need to specify which one to use using the user-service-ref attribute, where the value is the name of your bean for UserDetailsService.

Persistent Token Approach

This approach is based on the article http://jaspan.com/improved_persistent_login_cookie_best_practice with some minor changes [1]. To use this approach with namespace configuration, you need to provide a reference to the datasource:

<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>

The database must contain a persistent_logins table created using the following SQL (or equivalent):

create table persistent_logins (username varchar(64) not null,
								series varchar(64) primary key,
								token varchar(64) not null,
								last_used timestamp not null)

Interfaces and implementations of the Remember-Me method

The Remember-me method is used with UsernamePasswordAuthenticationFilter and is implemented using interceptors in the AbstractAuthenticationProcessingFilter superclass. It is also used in BasicAuthenticationFilter. Interceptors will call specific RememberMeServices at appropriate times. The interface looks like this:

Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
void loginFail(HttpServletRequest request, HttpServletResponse response);
void loginSuccess(HttpServletRequest request, HttpServletResponse response,
    Authentication successfulAuthentication);

Please refer to the Javadoc for a more complete description of how these methods work, although at this stage note that AbstractAuthenticationProcessingFilter only calls the loginFail() and loginSuccess(). The autoLogin() method is called by the RememberMeAuthenticationFilter whenever the SecurityContextHolder does not contain an Authentication. Therefore, this interface provides a basic implementation of remember-me with proper notification of authentication-related events and delegates authority to it in cases where a candidate's web request may contain a cookie and needs to be remembered. This structure allows you to use any number of remember-me implementation strategies. We learned above that Spring Security provides two implementations. We'll look at them one by one.

TokenBasedRememberMeServices

TokenBasedRememberMeServices generates a RememberMeAuthenticationToken, which is handled by the RememberMeAuthenticationProvider. The key instance is shared between this authentication provider and TokenBasedRememberMeServices. Additionally, TokenBasedRememberMeServices requires an instance of UserDetailsService from which it can obtain the username and password for signature matching, as well as generate a RememberMeAuthenticationToken so that it contains the correct GrantedAuthority. The application must provide some kind of logout command that will invalidate the cookie if the user requests it. TokenBasedRememberMeServices also implements the LogoutHandler interface from Spring Security, so can be used in conjunction with LogoutFilter to automatically clear cookies.

The following are the beans that must be in the application context in order to enable remember-me services:

<bean id="rememberMeFilter" class=
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>
<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class=
"org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="springRocks"/>
</bean>

Don't forget to add the RememberMeServices implementation to the UsernamePasswordAuthenticationFilter.setRememberMeServices() property, add RememberMeAuthenticationProvider to the AuthenticationManager.setProviders() and add RememberMeAuthenticationFilter to FilterChainProxy (usually right after UsernamePasswordAuthenticationFilter).

PersistentTokenBasedRememberMeServices

This class can be used in the same way as TokenBasedRememberMeServices, but additionally you need to add a PersistentTokenRepository to the configuration to store tokens. There are two standard implementations.

  • InMemoryTokenRepositoryImpl, which is intended for testing only.

  • JdbcTokenRepositoryImpl, which stores tokens in the database>