In this article, we will learn about the Spring Security remember me authentication. We will take a look at the cookie and token based remember me service and learn how it works internally in Spring Security.
Spring Security Remember Me Authentication
Remember me is a feature for any web application where it remember the user between different visits and will automatically log you in if it finds the correct information. You must have seen this while using Gmail or Amazon etc. where once you login, it will keep you login (if you select remember me option) and when you visit these sites next time, it will do a auto login for you.Spring security provides services to enable this feature.
Technically, this feature works with the help of browser cookies. Once you select the remember me option during your initial login, system will perform the following operations:
- Create a remember me cookie with the help of username and password. (Cookie will have expiration period)
- Hash the cookie and send it back to the browser.
- In next visit, if the cookie is detected and if its valid, system will perform an auto login for you.
Spring security remember me authentication provides the support for the following 2 options
- Remember me authentication using cookie.
- Token based remember me authentication.
In this article, we will take a look at both the options and will work on spring Security remember me examples.
1. Cookie Based Remember me Authentication
This is the most basic remember me authentication supported by Spring security. Spring security will create a cookie using the hashing once user is authenticated and sent it back to the browser. In order to generate this cookie, Spring security will be the following parameters.
- username.
- password.
- ExpirationTime
- a private key.
Here is a high level overview of the hashing:
base64(username + ":" + expirationTime + ":" +
md5Hex(username + ":" + expirationTime + ":" password + ":" + key))
To activate the cookie based remember me authentication, we need to add the following configuration in the Spring Security configuration class:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/register")
.permitAll()
.antMatchers("/account/**").hasAuthority("USER")
.and()
.rememberMe().userDetailsService(this.userDetailsService)
....
}
Line .rememberMe().userDetailsService(this.userDetailsService)
activate the remember me service.Once we run the application and perform the first login, spring security will perform the following additional work for us (once authentication is successful).
- Create authentication token.
- Generate remember me cookie and sent it back to the browser.
The next visit will read this browser cookie and if the cookie is valid, it will perform the auto login.If you are working with XML based configuration, you need to add the following line in your spring security configuration XML file.
<http>
...
<remember-me />
</http>
1.1 HTML Changes
We need to make change in UI order spring security remember me service work correctly.Spring security require following changes for the remember me service.
- Create a checkbox in the login page.
- The name of checkbox should be “remember-me“.
This is how the login page looks like with “Remember me option”
<form th:action="@{/login}" method="post">
<div th:if="${param.error}">
</div>
<div class="input-group mb-3">
<input type="email" class="form-control" name="username" placeholder="Email" autocomplete=”off”>
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-envelope"></span>
</div>
</div>
</div>
<div class="input-group mb-3">
<input type="password" name="password" class="form-control" placeholder="Password">
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-8">
<div class="icheck-primary">
<input type="checkbox" id="remember" name="remember-me">
<label for="remember">
Remember Me
</label>
</div>
</div>
<!-- /.col -->
<div class="col-4">
<button type="submit" class="btn btn-primary btn-block">Sign In</button>
</div>
<!-- /.col -->
</div>
</form>
1.2 Testing
Let’s run our application and see this in action. Once your application is up and running, please open the login page and perform the login by selecting the “remember me” option. Also take a look at the browser cookies.
If we look at the cookies, there is only JSESSIONID cookie which is the standard application server cookie. Let’s perform the login and check the cookies again:
As seen, “remember-me” cookie was created with expiration time. If you want to test if the login is working find, delete the JSESSIONID cookie and refresh the page, if the cookie is valid, system will perform an auto-login.
1.3 Security Issue
The Spring security cookie based remember me authentication comes with some security challenges and this approach is not recommended for your production system. Here are some of the security issue with this approach.
- Since this is in memory cookie (no information saved in database), if someone get holds of the remember me cookie, they can perform auto login on your behalf. They just need to send this cookie as part of the login request.
- The token will remain valid until
- It passes the expiration time.
- We change the password for our account.
2. Spring Security Remember me Persistent Token
This is the preferred approach and it provides additional security check while generating the remember me cookie.Spring security store some information in the database before generating the browser cookie. In this case, during the auto login process , spring security will fetch information from the database based on the provided remember me cookie and will allow auto login only if the information and user details are matching. To start, we need the following additional steps to use persistent token based remember me service.
- Database table to store persistent token information.
- Persistent Token repository to sore and fetch the tokens.
2.1 Persistent Token Table
To use this approach, we need to create a persistent_logins
table in the database, use the following SQL script to generate the table structure.
create table persistent_logins (username varchar(64) not null,
series varchar(64) primary key,
token varchar(64) not null,
last_used timestamp not null)
This is how the table might look like once we execute the script:
2.2 PersistentTokenRepository
In order for spring security to save and retrieve persistent token for remember me authentication, we need to provide PersistentTokenRepository
to the remember me service. Our PersistentTokenRepository
is an implementation for the JdbcTokenRepositoryImpl
and need the data source information (Database configuration defined in the application.properties
file)
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource);
return db;
}
In the last step, we need to pass the PersistentTokenRepository
to the RememberMeServices
.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/register")
.permitAll()
.antMatchers("/account/**").hasAuthority("USER")
.and()
.rememberMe().tokenRepository(persistentTokenRepository())
.and()
.formLogin()
.defaultSuccessUrl("/account/home")
.loginPage("/login")
.failureUrl("/login?error=true")
.and()
.logout().deleteCookies("dummyCookie");
}
If you are working with XML based configuration, you need to define the PersistentTokenRepository
and pass it to the remember-me service.
<http>
...
<remember-me data-source-ref="persistentTokenRepository"/>
</http>
2.3 Testing
Start the application and on the login screen, select “remember me” option. Once you do a login, you will see the remember-me cookie in the browser. It is similar to what we saw in section one, however check the persistent_logins
table in the database:
In this case the token information is saved in the database. If you compare it with the cookie sent to the browser, you will see that it does to match with the token or the series information saved n the database.
The browser cookie contains information about both token and series and the Spring security RememberMeServices
will decode and try to match it with the information saved in the database.
3. Spring Security Remember Me Workflow
For those who want to have a look at the internal workflow of the remember me functionality, here is overall workflow.I think the workflow give all information and don’t need any additional discussion.
4. Remember me Authentication and UserDetailsService
The UserDetailsService is required for both the remember me authentications.If we have UserDetailsService
in the application, Spring security will automatically picks it up. In case of multiple services, we need to pass it to the remember me service.
5. Remember me Service Customization
The Spring security remember me default are sensible enough and fulfill most of the use cases, however, spring security provide the flexibility to customize the remember me workflow. Let’s take a look at some of the customization that can be done with this service.
rememberMeCookieDomain
– If you want to generate cookie for a specific domain or subdomain. The cookie will only be visible for this domain.rememberMeCookieName
– The name of cookie which store the token for remember me authentication. Default name is “remember-me”.userDetailsService
– If you have multiple userDetailsService, pass a specific servicerememberMeServices
– Custom remember me service optiontokenValiditySeconds
– Cookie validation in seconds. You can use it to make it configurable.useSecureCookie
– If you want to mark this as secure cookie. Remember that secure cookies can only be sent over HTTPS
To customize, just extend your Spring security configuration class:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/register")
.permitAll()
.antMatchers("/account/**").hasAuthority("USER")
.and()
.rememberMe().tokenRepository(persistentTokenRepository())
.rememberMeCookieDomain("domain")
.rememberMeCookieName("custom-remember-me-cookie")
.userDetailsService(this.userDetailsService)
.rememberMeServices(null)
.tokenValiditySeconds(2000)
.useSecureCookie(true)
.and()
.formLogin()
.defaultSuccessUrl("/account/home")
.loginPage("/login")
.failureUrl("/login?error=true");
}
Summary
In this article, we talked about the Spring Security remember me authentication. We covered the following important points in this article.
- What is remember me authentication and how it works?
- How to implement cookie based remember me authentication in Spring security?
- What are the security limitation of cookie based remember me authentication.
- How to implement persistent token remember me service in Spring security.
- Workflow for the persistent token remember me service.
This article is part of our Spring security course and the source code is available on the GitHub.