
In Java development, protecting user accounts and sensitive data is a top priority. With threats constantly evolving and becoming more advanced, using secure methods isn’t just a good idea; it’s essential. Traditional username and password authentication alone is no longer sufficient to defend against intensified cyber threats like session hijacking and replay attacks. A great way to enhance login security is by using one-time tokens, which add an extra layer of defense. Implementing one-time tokens significantly enhances the security of the login process, offering better protection for users. In Java applications, this type of security is achieved using Spring Security, a powerful and flexible framework specifically designed to secure Java-based apps. By leveraging Spring Security and one-time tokens, a Java development company can create secure, reliable, and user-friendly applications. It demonstrates their commitment to protecting user data and resilience against cyber threats.
In this blog, we’ll explore how to implement one-time token authentication using Spring Security and how it can assist Java development teams in building secure, user-centric applications in an increasingly threat-prone environment.
1. What is Spring Security?
Spring Security is a significant and highly customizable framework for authentication and access control in Java applications. It is a module of the giant Java Spring Framework ecosystem and is widely used to secure enterprise-level applications. It works through a series of different filters in the web application’s filter chain. Each filter has a specific responsibility, such as checking the login credentials, handling CSRF tokens, or processing security headers. These filters are arranged in a specific line, and each web request passes through this line before reaching the application’s controllers.
Spring Security works on the following core principles:
- Authentication: Authentication is the process of verifying a user’s identity by evaluating the username and password credentials. These credentials are encapsulated inside an Authentication object. The AuthenticationManager processes this and returns a fully authenticated object if the credentials are valid. The principal represents the currently authenticated user.
- Authorization: It is one step further from authentication. Once the user is authenticated, they must be authorized to access specific resources. Spring Security evaluates what they’re allowed to do, i.e., if the user is equipped with the necessary roles or authorities to access particular resources or perform certain actions.
- SecurityContext: SecurityContext holds security-related information for the current request, like the authenticated user (principal).
- Filter Chain: Spring Security uses a filter chain, i.e., a sequence of servlet filters, to apply security checks to every request.
- WebSecurityConfigurerAdapter: WebSecurityConfigurerAdapter is an abstract class that permits users to override methods to customize security settings such as authentication, authorization, and HTTP security. Spring Security integrates with Spring Web MVC, allowing authentication details to be injected into controllers.
- UserDetailsService: UserDetailsService is an interface in Spring Security that loads user-specific data during the authentication process. It generally fetches user details like username, password, and roles from a database or other source.
- Password Storage: The PasswordEncoder interface is used for encoding and verifying passwords, ensuring secure storage and comparison.
- AuthenticationManager: AuthenticationManager is a core interface in Spring Security used to process authentication requests. It validates user credentials and returns an Authentication object if successful.
- AuthenticationProvider: AuthenticationProvider is an interface in Spring Security that is responsible for processing authentication requests. It verifies the user’s credentials and returns an Authentication object if the credentials are correct, or throws an exception if they are incorrect.
2. Why Use Spring Security?
Some key reasons to use Spring Security include:
- Extensive Built-in Security Capabilities: Spring Security offers a comprehensive suite of features right out of the box, covering authentication, access control, and defenses against common vulnerabilities and attacks.
- Seamless Spring Framework Integration: It works effortlessly with other Spring framework modules like Spring MVC and Spring Boot, making it easier to build secure applications within the broader Spring environment.
- Highly Configurable and Adaptable: Developers can tailor Spring Security to fit their specific needs, whether that involves creating custom login flows or implementing detailed permission rules.
- Proven and Widely Used: As one of the most popular security frameworks in the Java community, Spring Security is a trusted solution relied upon by countless developers and enterprises worldwide.
3. Key Features of Spring Security
- Session Management: It helps prevent session fixation, limits concurrent sessions, and supports features like session timeout and remember-me functionality.
- LDAP Authentication: LDAP is the Lightweight Directory Access Protocol. It allows applications to authenticate users against an LDAP server, for example, Active Directory. It uses Spring’s built-in support to validate credentials, retrieve user details, and manage roles or groups defined in the directory. Configuration can be done via Java or XML using LdapAuthenticationProvider.
- Web Security: Spring Security provides built-in defenses against common web threats, such as Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF), which block unauthorized actions on users’ behalf.
- Remember-Me Authentication: Remember-me functionality allows users to remain logged in even after closing the browser. It works by storing a token, usually in a cookie, which automatically re-authenticates the user on their next visit. Spring Security supports both in-memory and persistent database-backed tokens. It’s useful for improving user experience in applications where frequent logins aren’t ideal.
- In-Memory Authentication: In-memory authentication lets you configure user details directly in the configuration without needing a database. You can set it up using Java configuration by defining users in a UserDetailsService bean. Passwords are usually encoded using a PasswordEncoder like BCryptPasswordEncoder.
4. One-Time Token Login: A New Feature in Spring Security
One-Time Token Login is a new feature in Spring Security that allows users to authenticate using a single-use, time-limited token. It’s ideal for scenarios like passwordless login, magic links, or temporary access without traditional credentials.
5. What is a One-Time Token Login?
One-Time Token Login is a feature that enables users to authenticate without using a password by providing them with a unique, time-limited token. This token is typically sent via email or SMS and remains valid only for a short period. When users click the link, they get system access.
The following is a flowchart depicting the workflow of the One-Time Token Login process.

- Login Page: The process starts at the default login page, created by Spring Security using formLogin(). This page contains a form for users to request a one-time token via oneTimeTokenLogin().
- Token Request: The user submits the form to request a one-time token for authentication.
- Token Generation: A unique one-time token is generated by the OneTimeTokenGenerationSuccessHandler and sent to the user’s email as a Magic Link.
- Magic Link: The user clicks the Magic Link in the email, which leads them to a submission page (generated by DefaultOneTimeTokenSubmitPageGeneratingFilter). If the token is in the URL, the user can observe that it is automatically filled.
- Authentication Failure: If the token is invalid or expired, the system will display an error to the user.
- Authentication Success: If the token is valid, the process results in a successful authentication, and the application is granted access. Finally, after passing through all necessary security filters, the request.
6. Why Use One-Time Token Login?
One-Time Token (OTT) login includes several advantages:
- Improved User Experience: Users are free from the overhead of remembering or entering passwords, making it easier and faster to log in. They just have to click their email or SMS link to gain access.
- Increased Security: One-time tokens are short-lived, so even if someone intercepts the token, it can’t be used after a short period.
- Reduced Risk of Password Theft: Since no password is used, there’s no risk of passwords being stolen or leaked through attacks like phishing.
- Ideal for Sensitive Applications: One-time tokens are ideal for sensitive applications because they provide a secure, passwordless authentication method that minimizes the risk of password theft or compromise.
- Stateless Authentication: The server does not require storing or managing session information between requests. Instead, each request is authenticated independently using a unique, time-sensitive token, which reduces server-side complexity.
7. Version Compatibility
The following table will help you understand the compatibility of different versions of Java Development Kit (JDK) with different Spring Security and Spring Boot versions.
Spring Security Version | Spring Boot Version | Java Version |
---|---|---|
5.0.x – 5.3.x | 2.2.x – 2.5.x | 8, 11 |
5.4.x | 2.6.x | 8, 11, 17 |
6.x (latest stable) | 3.x (latest stable) | 17+ |
8. How to Implement One-Time Token Login With Spring Security?
Spring Security’s One-Time Token Login feature can be seamlessly integrated into a Spring application using its built-in Domain Specific Language(DSL). Let’s understand the complete procedure in a step-by-step manner below.
Step 1: Add Necessary Dependencies in pom.xml
To begin implementing one-time token login, start by adding the required dependencies to your project. You’ll need Spring Security to handle the authentication framework and Spring Mail to send the magic link to the user’s email. These dependencies allow you to secure your application and deliver one-time login links effectively. You can include them in your pom.xml file. Once these libraries are in place, you’ll be ready to configure email sending, generate one-time tokens, and integrate them into your custom authentication flow.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.4.3</version> <relativePath/> </parent> <groupId>com.tatvasoft</groupId> <artifactId>one-time-token-login</artifactId> <version>0.0.1-SNAPSHOT</version> <name>one-time-token-login</name> <description>One-time token login using Spring Security</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.36</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project> |
Step 2: Configure Spring Security with One-Time Token Login
Next, we need to configure Spring Security to enable one-time token login using the oneTimeTokenLogin() DSL. This DSL allows us to specify how the token is generated, validated, and used.
package com.tatvasoft.configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.userdetails.User; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfiguration { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(request -> request .requestMatchers("/login/ott/**") .permitAll() .anyRequest() .authenticated() ) .formLogin(Customizer.withDefaults()) .oneTimeTokenLogin(Customizer.withDefaults()) .build(); } @Bean public InMemoryUserDetailsManager inMemoryUserDetails(){ InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager(); userDetailsManager.createUser( User .builder() .username([Your email]) .password("{NoOpPasswordEncoder}password") .build() ); return userDetailsManager; } } |
Note:
Spring Security, by default, uses the InMemoryUserDetailsManager to store user credentials like usernames and passwords in memory. This approach is suitable for testing or small applications due to its ease of use and minimal setup. However, for real-world scenarios, it is recommended to use a database-backed user store by implementing the UserDetailsService interface. As a result, you get a strong hold over user data and security policies.
Rather than relying on the default login process, Spring Security lets you define custom authentication filters. This is especially helpful when implementing unique login flows, like one-time token (OTT) authentication, or when you want a custom login page and authentication handler tailored to your application’s user experience.
You can also create your authentication providers to handle token or credential validation based on your business rules. Spring Security’s flexible architecture allows you to insert custom filters into the security chain, enabling you to control every aspect of how authentication and authorization are handled and customize it to match your application’s requirements.
Step 3: Configure the Mail Sender Properties
To send the email with the magic link, you must configure the JavaMailSender in your application.properties file.
spring.application.name=one-time-token-login #Email configuration spring.mail.host = smtp.gmail.com spring.mail.username = [Your Email] spring.mail.password = [Your Password] spring.mail.port = 587 spring.mail.properties.mail.smtp.auth = true spring.mail.properties.mail.smtp.starttls.enable = true spring.mail.properties.mail.smtp.starttls.required = true |
Step 4: Handle Token Generation Success
After generating the token, we need to manage the process of delivering it to the user. In this case, we’ll send the token to the user as a magic link through email. This is achieved using the TokenGenerationSuccessHandler.
TokenGenerationSuccessHandler:
package com.tatvasoft.configuration; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.ott.OneTimeToken; Importorg.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler; import org.springframework.security.web.util.UrlUtils; import org.springframework.stereotype.Component; import org.springframework.web.util.UriComponentsBuilder; import java.io.IOException; @Component @RequiredArgsConstructor public class TokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { private final MyMailSender mailSender; @Override public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken) throws IOException, ServletException { String email = oneTimeToken.getUsername(); UriComponentsBuilder builder = UriComponentsBuilder .fromUriString(UrlUtils.buildFullRequestUrl(request)) .replacePath(request.getContextPath()) .replaceQuery(null) .fragment(null) .path("/login/ott") .queryParam("token", oneTimeToken.getTokenValue()); String magicLink = builder.toUriString(); this.sendTokenLoginMail(email, magicLink); response.sendRedirect(magicLink); } private void sendTokenLoginMail(String email, String loginLink) { String message = "<html><body>" + "<div style='max-width:400px; background-color : #fefefe;'>" + "<div style='padding:10px'>" + "<h2>Login to Your Account</h2>" + "<h3>Hello " + email + ",</h3>" + "<p>Click the link below to log in to your account. This link is valid for a short time and can only be used once.</p>" + "<a href='" + loginLink + "'>Login now</a>" + "<p>If you didn’t request this, please ignore this email. Your account is still secure.</p>" + "<p>If you have any questions, feel free to contact us.</p>" + "<br>" + "<p>Best regards,</p>" + "</div>" + "</div>" + "</body>" + "</html>"; String subject = "One time login link"; mailSender.sendMail(email, message, subject); } } |
Note:
By default, Spring Security provides built-in functionality for managing the generation and consumption of one-time tokens, commonly used for one-time passwords. However, if you need more flexibility, you can customize the token handling process by overriding the handle() and consume() methods in the OneTimeTokenService interface.
Token Generation: The handle() method can be customized to control how a one-time token is created and delivered to users. You can add custom logic, such as defining the token’s expiration time, attaching extra information to the token, or adjusting how the token is sent to the user.
Token Consumption: The consume() method can also be overridden to control how tokens are validated when used. This enables you to implement custom checks, such as verifying whether the token has already been used or if it has expired, ensuring that tokens are only valid for their intended purpose.
Step 5: Configure the Mail Sender
To send the email, you can create a reusable mail message preparator that accepts the recipient’s email, message content, and subject as inputs and uses them to send the email.
package com.tatvasoft.configuration; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.mail.javamail.MimeMessagePreparator; import org.springframework.stereotype.Component; @Slf4j @Component @RequiredArgsConstructor public class MyMailSender { private final JavaMailSender mailSender; @Value("${spring.mail.username}") private String FROM_EMAIL; public void sendMail(String email, String message, String subject) { try { MimeMessagePreparator mimeMessage = mimeMessagePreparator(subject, message, email); mailSender.send(mimeMessage); } catch (Exception e) { log.error(e.getLocalizedMessage()); } } public MimeMessagePreparator mimeMessagePreparator(String subject, String message, String email) { return mimeMessage -> { MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, false, "UTF-8"); helper.setFrom(FROM_EMAIL); helper.setTo(email); helper.setSubject(subject); helper.setText(message, true); }; } } |
Note:
You can also use a simple mail message to prepare and send mail messages.
Step 6: Token Verification and Authentication
When the user clicks the magic link sent to their email, they are directed to a token verification page. On this page, the token may be auto-filled from the link, or the user can manually enter it. If the token is verified as valid, the user is successfully authenticated and then redirected to the designated success page within the application.
Below are the outputs:
1. Login

2. Email

3. Token Verification

4. Success Welcome Page

9. Final Thoughts
Implementing authentication with a one-time token using Spring Security offers a modern, safe, and user-friendly alternative to conventional password-based logins. It enhances security by eliminating the risks associated with password storage and reuse, and it provides a smooth login experience through time-sensitive magic links. With Spring Security’s flexibility, developers can easily customize token generation, delivery, and validation to meet specific application needs. As security threats continue to grow more sophisticated, adopting one-time token authentication is a proactive and effective way to safeguard user data and build trust in your application.
Comments
Leave a message...