Spring Security OneTimeToken

How can we use one time token with spring security and spring boot.

Starting from Spring Security 6.4 it now supports One-Time Token (OTT) authentication via the oneTimeTokenLogin() DSL.

One-time token is a way where user can log in the system through EMAIL or SMS. They don't need to use a password to do it.

How does It work?

  • User enters his username/email and requests for one-time token.

  • Spring security validates the user's existence, generates token and sends a one-time token login link to their corresponding email or phone number.

  • The user receives the link and by clicking it, he redirects to the link, where he does login with the token provided.

  • The system validates the token, do the authentication process and allows him to view the secured content.

Classes involved in the token generation

oneTimeTokenLogin() dsl

  • It is a functional method that is used to configure one time token login in spring security.

  • It takes OneTimeTokenLoginConfigurer customizer as parameter.

OneTimeTokenLoginConfigurer

  • It's a configurer class that is used to configure one time token login dsl.

  • It provides default methods and configuration properties that are helpful in defining the one time token login configuration.

  • Here are the classes and the properties defined-

private OneTimeTokenService oneTimeTokenService = new InMemoryOneTimeTokenService();

private AuthenticationConverter authenticationConverter = new OneTimeTokenAuthenticationConverter();

private AuthenticationFailureHandler authenticationFailureHandler = new SimpleUrlAuthenticationFailureHandler();

private AuthenticationSuccessHandler authenticationSuccessHandler = new SavedRequestAwareAuthenticationSuccessHandler();

private String defaultSubmitPageUrl = "/login/ott"; // default login page for ott, can be changed to custom one but need to handle csrf

private boolean submitPageEnabled = true; // enabled/disabled the submit page for ott

private String loginProcessingUrl = "/login/ott"; // url to process token, and gets called after varification

private String tokenGeneratingUrl = "/ott/generate"; // configured the ott token generator, in memory, jdbc

private OneTimeTokenGenerationSuccessHandler oneTimeTokenGenerationSuccessHandler = new RedirectOneTimeTokenGenerationSuccessHandler();

private AuthenticationProvider authenticationProvider = new OneTimeTokenAuthenticationProvider();

GenerateOneTimeTokenFilter

  • It's a filter that processes one-time token request with ant path matcher /ott/generate.

  • It has the OneTimeTokenService and OneTimeTokenGenerationSuccessHandler configured that helps in filtering the request.

  • It checks if request is for /ott/generate then validates the user and generates the one-time token and pass it to one time token success handler.

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
       throws ServletException, IOException {
    if (!this.requestMatcher.matches(request)) {
       filterChain.doFilter(request, response);
       return;
    }
    String username = request.getParameter("username");
    if (!StringUtils.hasText(username)) {
       filterChain.doFilter(request, response);
       return;
    }
    GenerateOneTimeTokenRequest generateRequest = new GenerateOneTimeTokenRequest(username);
    OneTimeToken ott = this.tokenService.generate(generateRequest);
    this.tokenGenerationSuccessHandler.handle(request, response, ott);
}

OneTimeTokenAuthenticationProvider

  • It is an AuthenticationProvider (I) implementation class, responsible for authenticating users based on one-time tokens.

  • It uses an OneTimeTokenService to consume tokens and an UserDetailsService to fetch user authorities.

  • It is configured by default when we will use oneTimeTokenLogin() dsl.

  • It has public Authentication authenticate(Authentication authentication){} method.

  • This method authenticates the user, validates the token and generates a OneTimeTokenAuthenticationToken with user details.

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    OneTimeTokenAuthenticationToken otpAuthenticationToken = (OneTimeTokenAuthenticationToken) authentication;
    OneTimeToken consumed = this.oneTimeTokenService.consume(otpAuthenticationToken);
    if (consumed == null) {
       throw new InvalidOneTimeTokenException("Invalid token");
    }
    UserDetails user = this.userDetailsService.loadUserByUsername(consumed.getUsername());
    OneTimeTokenAuthenticationToken authenticated = OneTimeTokenAuthenticationToken.authenticated(user,
          user.getAuthorities());
    authenticated.setDetails(otpAuthenticationToken.getDetails());
    return authenticated;
}

DefaultLoginPageGeneratingFilter

  • It is a filter responsible for generating the HTML pages for various login request.

  • It generates templates for- login, token generation, token verification, ouath2 and passkeys.

  • It generates the pages based on the flag passed in security config like formLogin().

DefaultOneTimeTokenSubmitPageGeneratingFilter

  • It is the filter that creates a default one-time token submit page.

  • If the request contains a token query parameter, then the page will automatically fill the form with the token value.

  • It gets invoked on URL - /login/ott [default submit url]

  • In the form it has the loggin processing url that url configured or to /login/ott [post]

  • It generates the page by capturing token from query path and gives continue button to user to login in the system.

OneTimeTokenAuthenticationConverter

  • It is an implementation of AuthenticationConverter that detects if the request contains a token parameter and constructs a OneTimeTokenAuthenticationToken with it.

public Authentication convert(HttpServletRequest request) {
    String token = request.getParameter("token");
    if (!StringUtils.hasText(token)) {
       this.logger.debug("No token found in request");
       return null;
    }
    return OneTimeTokenAuthenticationToken.unauthenticated(token);
}

SimpleUrlAuthenticationSuccessHandler

  • It is an implementation class of AuthenticationSuccessHandler (I) .

  • It gets invoked upon successful authentication of the token and then redirects to the page configured.

  • It checks for the URL that user configured and redirects to it.

SimpleUrlAuthenticationFailureHandler

  • It is an implementation class of AuthenticationFailureHandler (I) .

  • It gets invoked upon authentication failure when onAuthenticationFailure and then redirects to the URL configured by defaultFailureUrl

  • It checks for the URL that user configured and redirects to it.

OneTimeTokenService

  • It is an Interface for generating and consuming one-time tokens.

  • It has implementation as -

    • InMemoryOneTimeTokenService - Contains map of username and token.

    • JdbcOneTimeTokenService - Stores info in database.

  • We can also implement our own one time token service.

  • By default, it sets the expiry time as 5 minutes.

OneTimeTokenGenerationSuccessHandler

  • It is an interface that users need to implement and do the work after token generation.

  • It has one method -

    public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken)
  • Once the token generated successfully, this method will get invoked where the user can send the token via mail or SMS.

  • After doing the process, the user can redirect to any success page that informs the user that the token got generated and delivered successfully.

Last updated