# Configure One-Time Passwords

Set up a passwordless experience using magic links and codes.

> For the index of this section of the site, see [llms.txt](https://fusionauth.io/docs/llms.txt)

To implement One-Time Passwords in your application, choose one of the following options:

*   hosted login pages: customizable using a theme and templates
*   passwordless API: fully customizable behavior since you call this API from your application

### Hosted Login Pages

Available since `1.59.0`

Hosted [Messenger](https://fusionauth.io/docs/customize/email-and-messages/messengers.md) passwordless logins are available in FusionAuth `1.59.0` and later.

You will need at least one Application with an OAuth redirect URL configured and the [Authorization Code grant](https://fusionauth.io/docs/lifecycle/authenticate-users/oauth.md#example-authorization-code-grant) enabled.

To implement one-time passwords using hosted login pages, complete the following steps:

1.  Choose the communication method(s) you want to use to send one-time passwords:
    
    *   To send over email, navigate to Tenants -> Email Templates and create an [Email Template based on our example](https://fusionauth.io/docs/customize/email-and-messages/message-templates-replacement-variables.md#passwordless-login).
    *   To send using a [Messenger](https://fusionauth.io/docs/customize/email-and-messages/messengers.md), navigate to Tenants -> Message Templates and create a [Message Template based on our example](https://fusionauth.io/docs/customize/email-and-messages/message-templates-replacement-variables.md#passwordless-login).
2.  Create the communication method:
    
    *   To communicate over email, navigate to Tenants -> Edit -> Email and configure your SMTP server. For testing, consider [mailcatcher](https://mailcatcher.me/).
    *   To communicate over a [Messenger](https://fusionauth.io/docs/customize/email-and-messages/messengers.md), navigate to Tenants -> Edit -> Identities and choose a Messenger. If you have not already configured a messenger, you can create one in Settings -> Messengers .
3.  Choose a default template for your phone or email communication in Tenants -> Edit -> Identities -> Template Settings . Use the **Passwordless login** option in the **Email** and **Phone** columns to control the default template for each separately.
    
4.  Enable one-time passwords in your Application by navigating to Applications -> Edit -> Security and enabling the **Enable passwordless login** checkbox:
    
    ![Enable passwordless login in the application Security tab.](https://fusionauth.io/img/docs/screenshots/passwordless-application-enable.png)
    
5.  Choose a strategy for each communication method you plan to use:
    
    *   **Clickable link**: Authenticate by visiting a link passed in the template, e.g. `${baseUrl}/oauth2/passwordless/${code}` -> `https://example.com/oauth2/passwordless/correct-horse-battery-staple`.
    *   **Form field**: Authenticate by entering a code passed in the template, e.g. `${oneTimeCode}` -> "123 456".
    
    ![Turn on passwordless login in the application Security tab.](https://fusionauth.io/img/docs/screenshots/passwordless-application-security.png)
    

To customize the look of the login pages, use [themes](https://fusionauth.io/docs/customize/look-and-feel.md). While editing the theme, you could remove the username/password form. This would force everyone to use one-time password authentication.

Changing a theme modifies it for all applications in a tenant, so these changes can affect the FusionAuth admin UI (if the new application is in the default tenant) and other applications in the same tenant.

Hide the username and password form for individual Applications

*   Use separate tenants.
*   Add logic to your theme to hide parts of the HTML based on the `client_id`.
*   Use [Application-specific themes](https://fusionauth.io/docs/customize/look-and-feel/application-specific-themes.md).

Limitations of hosted login pages

*   You can only communicate using email or a [Messenger](https://fusionauth.io/docs/customize/email-and-messages/messengers.md).
*   You must use the [Authorization Code grant](https://fusionauth.io/docs/lifecycle/authenticate-users/oauth.md#example-authorization-code-grant).

### Passwordless API

You can use the [Passwordless API](https://fusionauth.io/docs/apis/passwordless.md) to implement one-time password authentication from your own application. This enables you to:

*   customize every part of the user login experience.
*   send the code using any method you choose, for instance a Slack direct message.

The Passwordless API requires an [API key](https://fusionauth.io/docs/apis/authentication.md) with at least the `POST` permission to the `/api/passwordless/start` endpoint.

1.  Start one-time password login by calling the [/api/passwordless/start](https://fusionauth.io/docs/apis/passwordless/start-passwordless-login.md) endpoint. Because this endpoint requires an API key, you must emit this request from a secure environment (likely your application backend, not a browser or app).
    
    Start Magic Link Login API call
    
    ```shell
    API_KEY=...
    REQUEST_PAYLOAD='{...}'
    curl  -H "Content-type: application/json" -H "Authorization: $API_KEY" https://local.fusionauth.io/api/passwordless/start -d "$REQUEST_PAYLOAD"
    ```
    
    Here's an example request payload:
    
    Start Magic Link Login Request JSON
    
    ```json
    {
      "applicationId": "10000000-0000-0002-0000-000000000001",
      "loginId": "jared@piedpiper.com",
      "loginIdTypes": [
        "email"
      ],
      "state": {
        "client_id": "10000000-0000-0002-0000-000000000001",
        "redirect_uri": "https://piedpiper.com/callback",
        "response_type": "code",
        "scope": "openid",
        "state": "CSRF123"
      }
    }
    ```
    
    The `state` property in the JSON is optional.
    
    If present, it is echoed back to your application at the end of the one-time password login workflow. This allows anonymous users to interact with your application, then log in and have data from their anonymous session available.
    
    For example, if you have a shopping site, you may want to allow a user to add items to their cart before they sign in. Once they have logged in, the `state` parameter can be used to associate their cart Id with the authenticated user. In this case, the `state` key might be set to a JSON object like this:
    
    ```json
    { "cart_id" : 1234 }
    ```
    
    The call to [/api/passwordless/start](https://fusionauth.io/docs/apis/passwordless/start-passwordless-login.md) begins the authentication process, and returns a response with a code:
    
    Start Magic Link Email Login Response JSON
    
    ```json
    {
      "code": "CynAUMCHLxCCAWyHXOVWPQd8ZY0a6U0e3YpYkT0MNxs"
    }
    ```
    
    Start Magic Link Phone Login Response JSON
    
    ```json
    {
      "code": "CynAUMCHLxCCAWyHXOVWPQd8ZY0a6U0e3YpYkT0MNxs",
      "oneTimeCode": "6258"
    }
    ```
    
    Possession of this one-time code authenticates the end user.
    
2.  Send the code. To send the code using a locale-aware template via Messenger or SMTP configuration in FusionAuth, call [/api/passwordless/send](https://fusionauth.io/docs/apis/passwordless/send-passwordless-login.md).
    
3.  The user enters the code. You must build an interface for them to do so. For email use cases, the email message will often contain a link to a form where the user can enter the `code`, or the link will hit an endpoint that processes the code.
    
    For phone number use cases, the typical pattern is for your application to present a form immediately after sending the code to the user. The `code` value can be available as a hidden field on a form, but the `oneTimeCode` value must be provided by the user.
    
4.  Complete the login via a call to [/api/passwordless/login](https://fusionauth.io/docs/apis/passwordless/complete-a-passwordless-login.md). You can pass other information such as IP address, but only the code is required.
    
    Complete Magic Link Email Login Request JSON
    
    ```json
    {
      "code": "CynAUMCHLxCCAWyHXOVWPQd8ZY0a6U0e3YpYkT0MNxs"
    }
    ```
    
    Complete Magic Link Phone Login Request JSON
    
    ```json
    {
      "code": "CynAUMCHLxCCAWyHXOVWPQd8ZY0a6U0e3YpYkT0MNxs",
      "oneTimeCode": "6258"
    }
    ```
    
    If the code (and for phone numbers, `oneTimeCode`) is valid, your application will receive user data, a JWT, and other data based on the application configuration. If you send a `state` property in the JSON when starting the authentication process, it will also be included in the response, under the `state` key.
    
    Complete Magic Link Response JSON
    
    ```json
    {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0ODUxNDA5ODQsImlhdCI6MTQ4NTEzNzM4NCwiaXNzIjoiYWNtZS5jb20iLCJzdWIiOiIyOWFjMGMxOC0wYjRhLTQyY2YtODJmYy0wM2Q1NzAzMThhMWQiLCJhcHBsaWNhdGlvbklkIjoiNzkxMDM3MzQtOTdhYi00ZDFhLWFmMzctZTAwNmQwNWQyOTUyIiwicm9sZXMiOltdfQ.Mp0Pcwsz5VECK11Kf2ZZNF_SMKu5CgBeLN9ZOP04kZo",
      "state": {
        "client_id": "10000000-0000-0002-0000-000000000001",
        "redirect_uri": "https://piedpiper.com/callback",
        "response_type": "code",
        "scope": "openid",
        "state": "CSRF123"
      },
      "user": {
        "active": true,
        "breachedPasswordLastCheckedInstant": 1471786483322,
        "breachedPasswordStatus": "None",
        "birthDate": "1976-05-30",
        "connectorId": "e3306678-a53a-4964-9040-1c96f36dda72",
        "data": {
          "displayName": "Johnny Boy",
          "favoriteColors": [
            "Red",
            "Blue"
          ]
        },
        "email": "example@fusionauth.io",
        "expiry": 1571786483322,
        "firstName": "John",
        "fullName": "John Doe",
        "id": "00000000-0000-0001-0000-000000000000",
        "identities": [
          {
            "insertInstant": 1742936980069,
            "lastLoginInstant": 1742936980069,
            "lastUpdateInstant": 1742936980069,
            "primary": true,
            "type": "email",
            "value": "example@fusionauth.io",
            "verified": false,
            "verifiedReason": "Disabled"
          },
          {
            "insertInstant": 1742936980069,
            "lastLoginInstant": 1742936980069,
            "lastUpdateInstant": 1742936980069,
            "primary": true,
            "type": "phoneNumber",
            "value": "+13035551212",
            "verified": false,
            "verifiedReason": "Disabled"
          },
          {
            "displayValue": "johnny123",
            "insertInstant": 1742936980069,
            "lastLoginInstant": 1742936980069,
            "lastUpdateInstant": 1742936980069,
            "moderationStatus": "ACTIVE",
            "primary": true,
            "type": "username",
            "value": "johnny123",
            "verified": false,
            "verifiedReason": "Unverifiable"
          }
        ],
        "imageUrl": "http://65.media.tumblr.com/tumblr_l7dbl0MHbU1qz50x3o1_500.png",
        "insertInstant": 1742936980069,
        "lastLoginInstant": 1742936980069,
        "lastName": "Doe",
        "middleName": "William",
        "mobilePhone": "303-555-1234",
        "passwordChangeRequired": false,
        "passwordLastUpdateInstant": 1742936980069,
        "phoneNumber": "+13035551212",
        "preferredLanguages": [
          "en",
          "fr"
        ],
        "registrations": [
          {
            "applicationId": "10000000-0000-0002-0000-000000000001",
            "data": {
              "displayName": "Johnny",
              "favoriteSports": [
                "Football",
                "Basketball"
              ]
            },
            "id": "00000000-0000-0002-0000-000000000000",
            "insertInstant": 1742936980069,
            "lastLoginInstant": 1742936980069,
            "preferredLanguages": [
              "en",
              "fr"
            ],
            "roles": [
              "user",
              "community_helper"
            ],
            "username": "johnny123",
            "usernameStatus": "ACTIVE",
            "verified": true,
            "verifiedInstant": 1742936980069
          }
        ],
        "timezone": "America/Denver",
        "tenantId": "f24aca2b-ce4a-4dad-951a-c9d690e71415",
        "twoFactor": {
          "methods": [
            {
              "authenticator": {
                "algorithm": "HmacSHA1",
                "codeLength": 6,
                "timeStep": 30
              },
              "id": "35VW",
              "method": "authenticator"
            },
            {
              "id": "V7SH",
              "method": "sms",
              "mobilePhone": "555-555-5555"
            },
            {
              "email": "example@fusionauth.io",
              "id": "7K2G",
              "method": "email"
            }
          ]
        },
        "usernameStatus": "ACTIVE",
        "username": "johnny123",
        "verified": true,
        "verifiedInstant": 1742936980069
      }
    }
    ```
    
    The user is now authenticated. Your application has user data, pre-existing state if provided, and a JWT which can be used to represent the user to other resources. If you want to send the JWT to a client as a cookie, you can now do so.
    

JWTs are typically passed to other systems like an API server to enable access to protected resources ([more about JWTs](https://fusionauth.io/articles/tokens.md)). If you are using one-time password authentication and are not using the JWT, you can turn off its generation. Creating and signing the JWT requires server resources; turning JWT generation off will improve performance.

To disable JWTs, set the `noJWT` parameter to true when you call the complete API endpoint.

## Two-Factor Authentication

You can combine FusionAuth one-time password authentication with [Multi-Factor Authentication (MFA/2FA)](https://fusionauth.io/docs/lifecycle/authenticate-users/multi-factor-authentication.md).

### Hosted Login Pages

When two-factor authentication is enabled, after the one-time password has been provided, FusionAuth will prompt the user to provide an additional verification code.

### Passwordless API

when you complete the one-time password authentication, instead of getting the user data, you'll get a `twoFactorId`:

```json
{"twoFactorId":"VnNILnXs_EDG-cjwokwITRApmAxCMkojeT3CUqqLhLc"}
```

Your application must then prompt the user for their two-factor code using whatever method they have defined. Pass the `twoFactorId` and the two-factor code to the [/api/two-factor/login](https://fusionauth.io/docs/apis/login/complete-mfa.md) endpoint in order to complete the two-factor authentication.

If a user has previously completed a two-factor authentication and has decided to trust the device, you may have a `twoFactorTrustId` value. This can be passed to the [/api/passwordless/login](https://fusionauth.io/docs/apis/passwordless/complete-a-passwordless-login.md) endpoint. If valid, this will skip the two-factor challenge.

## Try One-Time Passwords

To test how your users would experience one-time passwords:

1.  Go to your application login page and click the Login with a magic link button
    
    ![The FusionAuth login page showing the Login with a magic link button.](https://fusionauth.io/img/docs/screenshots/passwordless-login-page.png)
    
2.  Enter the user's unique identifier (email address, phone number, or username).
    
3.  Check your secure communication method of choice for the one-time password.
    
4.  Click the link or enter the code into the form.
    
    ![Entering the one-time code into the form.](https://fusionauth.io/img/docs/screenshots/passwordless-phone-otp-form.png)
    

As soon as the one-time password is used, the user has begun an Authorization Code grant. You can [consume the authorization code](https://fusionauth.io/docs/lifecycle/authenticate-users/oauth.md#example-authorization-code-grant) using a library or your own code. Whatever you would normally do if someone signed in with a password, you can now do here. This means that you'll be provided with the same refresh tokens, user data, or JWTs that would be delivered if the user had signed in with a password.

## Troubleshooting

Every time you start a one-time password login for a given user, FusionAuth invalidates all other codes for that user. Codes are also invalidated after a configurable time limit.

If a user provides a code that is invalid, if their account is locked, or if there is any other issue in the request, a status code in the 400 range will be returned. Please consult the [passwordless API reference docs](https://fusionauth.io/docs/apis/passwordless/complete-a-passwordless-login.md#response-3) for more details about return status codes.
---

## Other pages in One Time Passwords

> For the full index of this section, see [Lifecycle](https://fusionauth.io/docs/llms-lifecycle.txt).

- [Customize One-Time Passwords](https://fusionauth.io/docs/lifecycle/authenticate-users/one-time-passwords/customize.md): Customize the one-time password experience in your application.
- [One-Time Passwords](https://fusionauth.io/docs/lifecycle/authenticate-users/one-time-passwords.md): Create a passwordless experience using magic links and one-time passwords.
