Login with Email OTP

One-time passcodes (OTPs) can be sent to users by email in order to authenticate existing users.

Check out our sample app

Note

This implements a backend-to-backend integration for authentication. See Backend Authentication APIs

How it works

Here's an example of an email OTP integration. Transmit APIs are shown in pink along with the relevant integration step.

Before you start

Before you start your integration, you'll need a Transmit application. See create an application

Note:

When creating an application, Redirect URIs is a required field. This flow doesn't use a redirect URI so you can simply add your website URL (e.g., https://your-domain.com)

Step 1: Sign up users

Before you can login users into your app, they will need to be created in your Transmit tenant and associated with your app. New users can be created using a POST /users request, which must include the user's email address. If the user already exists in your Transmit tenant but isn't yet associated with your app, this request will just add the user to your app (but won't update any other details).

Note:
  • You'll need a valid client access token to authorize the request. See Get client access tokens
  • The user's email address will marked as verified upon their first email-based authentication.

Step 2: Send email OTP

Use a backend send request like the one below to send an email OTP to the user's email. To customize the email, see Next steps. If the request succeeds, an OTP is sent to the user's email and a 200 response is returned.

Note
  • You'll need a valid client access token to authorize the request. See Get client access tokens
  • The example below identifies the user using their email, but other identifier types can be used instead (phone number, user ID, or username).
Copy
Copied
import fetch from 'node-fetch';

async function run() {
  const resp = await fetch(
    `https://api.transmitsecurity.io/cis/v1/auth/otp/send`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: 'Bearer [ACCESS_TOKEN]' // Client access token
      },
      body: JSON.stringify({
        channel: 'email',
        identifier_type: 'email', // User is identified by email (other options available)
        identifier: '[EMAIL]' // User's email address (unless another type is used)
      })
    }
  );

  const data = await resp.json();
  console.log(data);
}

run();

Step 3: Authenticate email OTP

Once the user enters the OTP they received, your client should send it to your app backend so it can be used to obtain user tokens. Create your backend endpoint that will receive this code and then send an OTP auth request like the one below. If successful, a 200 response will be returned with the user tokens, which should be validated as described here.

Note

You'll need a valid client access token to authorize the request. See Get client access tokens

Copy
Copied
import fetch from 'node-fetch';

async function run() {
  const resp = await fetch(
    `https://api.transmitsecurity.io/cis/v1/auth/otp/authenticate`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: 'Bearer [ACCESS_TOKEN]' // Client access token
      },
      body: JSON.stringify({
        passcode: '[OTP]', // OTP entered by the user
        identifier_type: 'email', // Same as the type in the send request
        identifier: '[EMAIL]' // Same as the identifier in the send request
      })
    }
  );

  const data = await resp.json();
  console.log(data);
}

run();

Here's an example of a successful response:

Copy
Copied
{
  "access_token": "string",
  "id_token": "string",
  "refresh_token": "string",
  "token_type": "string",
  "expires_in": 3600,
  "session_id": "string"
}

Next steps

Once you've completed a basic integration, here are some customizations you can consider:

Email customization

The default email template for Login can be customized either from the Admin Portal or via API (but not both). From the Admin Portal (Authentication > Authentication methods > One-time passcodes), you can customize the color of the email address that appears in the message. The email message will use the application's logo and name (see screenshot below). The subject, text and appearance can also be customized using the email_content object in the send request.

Note

If you pass the email_content object, all the email branding will be taken from there and the default template won't be used at all. This means that if a field is not specified, it will be treated as empty.

Here is a screenshot of the email templates with their customizable field names:

OTP settings

From the Admin Portal ( Authentication > Authentication methods > One-time passcodes), you can configure the OTP policy for your app:

  • Expiration time : set the OTP expiration period in minutes.
  • Failed attempts lockout policy : set the number of failed login attempts that trigger a temporary user lockout and specify the lockout duration in minutes.
  • Code length : set the length of the one-time code.

Custom email provider

In the Admin Portal (from Settings > Email Provider), you can configure to use your custom email provider (e.g., SMTP or SendGrid) instead of the Transmit default.

Security considerations

To secure your OTP implementation, here are some recommendations.

Guidelines
  • Verify the user's email address upon sign up. For example, perform a magic link authentication as part of the onboarding flow (after creating the user in Transmit).
  • To prevent credential harvesting, your backend shouldn't indicate to the client if the user wasn't found.