# Spring Security OneTimeToken

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.
* &#x20;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-

{% code fullWidth="true" %}

```java
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();
```

{% endcode %}

### GenerateOneTimeTokenFilter

* It's a filter that processes one-time token request with ant path matcher **/ott/generate.**&#x20;
* 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.

{% code fullWidth="true" %}

```java
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);
}
```

{% endcode %}

### 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.

{% code fullWidth="true" %}

```java
@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;
}
```

{% endcode %}

### 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.&#x20;
* 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`  \[**&#x64;efault submit url]
* In the form it has the loggin processing url that url configured or to **`/login/ott [post]`**&#x20;
* 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.

<pre class="language-java"><code class="lang-java"><strong>public Authentication convert(HttpServletRequest request) {
</strong>    String token = request.getParameter("token");
    if (!StringUtils.hasText(token)) {
       this.logger.debug("No token found in request");
       return null;
    }
    return OneTimeTokenAuthenticationToken.unauthenticated(token);
}
</code></pre>

### 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&#x20;

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

* It has implementation as -&#x20;

  * **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 -&#x20;

  ```java
  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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wisdom.gitbook.io/gyan/security/passwordless-login-with-spring-security-6/spring-security-onetimetoken.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
