Skip to main content
Authsignal SDKs can be used to implement WhatsApp OTP challenges in two scenarios.
  1. Sign-in. Use our Server SDKs to authenticate users with WhatsApp OTP as the 1st factor. This integration only requires a phone number to initiate.
  2. Adaptive MFA. Use Server SDKs together with Client SDKs to authenticate users with WhatsApp OTP as a secondary factor. This integration requires a user ID to initiate and assumes the user has already been authenticated with a primary factor.

Portal setup

  1. Navigate to Authenticators in the Authsignal Portal, find WhatsApp, and click Set up.
  2. Choose and set up a WhatsApp Provider you want to use in the next screen. Then click Connect Account.

SDK setup

Server SDK

Initialize the SDK using your secret key from the API keys page and the API URL for your region.
import { Authsignal } from "@authsignal/node";

const authsignal = new Authsignal({
  apiSecretKey: "YOUR_SECRET_KEY",
  apiUrl: "YOUR_API_URL",
});

Client SDK

Initialize the Web SDK or Mobile SDK using your tenant ID from the API keys page and your API URL.
import { Authsignal } from "@authsignal/browser";

const authsignal = new Authsignal({
  tenantId: "YOUR_TENANT_ID",
  baseUrl: "YOUR_API_URL",
});

Sign-in

Scenario - Let users sign-in with WhatsApp OTP as the 1st factor.
Our Server SDKs include methods to initiate and verify a WhatsApp OTP challenge for a given phone number. These methods are well-suited for passwordless sign-in scenarios where you need to authenticate a user based on their phone number.

1. Initiate challenge

Call Initiate Challenge to send an OTP to a phone number.
const request = {
  verificationMethod: "WHATSAPP",
  action: "signInWithWhatsApp",
  phoneNumber: "+64270000000",
};

const response = await authsignal.challenge(request);

const challengeId = response.challengeId;
You can choose a value for the action here which best describes what the user is doing in your app (e.g. signing in with WhatsApp). It will be used to track user activity in the Authsignal Portal.

2. Verify challenge

Once the user inputs the OTP code, call Verify Challenge to verify it.
const request = {
  challengeId: "3a991a14-690c-492b-a5e5-02b9056a4b7d",
  verificationCode: "123456",
};

const response = await authsignal.verify(request);

const isVerified = response.isVerified;

3. Claim challenge

Now that the challenge has been verified, you can lookup the user in your IdP or DB based on their phone number. For passwordless flows with a combined sign-up and sign-in UX, you may need to create the user at this point if no account exists. Then claim the challenge once you know the primary user ID associated with the phone number.
const request = {
  challengeId: "3a991a14-690c-492b-a5e5-02b9056a4b7d",
  userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
};

const response = await authsignal.claimChallenge(request);
This final step is important because it attributes activity to the correct user and ensures observability in the Authsignal Portal.

Adaptive MFA

Scenario - Challenge users with WhatsApp OTP as a 2nd factor and use rules to decide when and where in your app to trigger the challenge.
The following steps demonstrate how to implement adaptive MFA with WhatsApp OTP - either at sign-in or as step-up authentication when the user performs a sensitive action in your app (e.g. making a payment).

1. Track action

Use a Server SDK to track an action in your backend. This step can apply rules to determine if a challenge is required.
  • Custom UI
  • Pre-built UI
const request = {
  userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
  action: "signIn",
  attributes: {
    phoneNumber: "+64270000000",
  },
};

const response = await authsignal.track(request);

if (response.state === "CHALLENGE_REQUIRED") {
  // Return token to your frontend to present challenge
  const token = response.token;
}
You can choose a value for the action here which best describes what the user is doing in your app (e.g. signIn or createPayment). Each action can have its own set of rules. To learn more about using rules and handling different action states refer to our documentation on actions and rules.

2. Present challenge

If the action state is CHALLENGE_REQUIRED then you can present a WhatsApp OTP challenge using the Web SDK or Mobile SDK.
  • Custom UI
  • Pre-built UI
// Set token from the track response
authsignal.setToken("eyJhbGciOiJ...");

// Send the user a WhatsApp OTP code
// You can call this multiple times via a 'resend' button
await authsignal.whatsapp.challenge();

// Verify the inputted code matches the original code
const response = await authsignal.whatsapp.verify({ code: "123456" });

// Obtain a new token
const token = response.token;

3. Validate action

Use the new token obtained from the client SDK to validate the action on your backend.
const response = await authsignal.validateChallenge({
  action: "signIn",
  token: "eyJhbGciOiJIUzI....",
});

if (response.state === "CHALLENGE_SUCCEEDED") {
  // User completed challenge successfully
}
If the action state shows that the WhatsApp OTP challenge was completed successfully, you can let the user proceed with the action.

Enrollment

Scenario - Enroll users in WhatsApp OTP while they’re authenticated so it can be used later as a method for adaptive MFA.
To use WhatsApp OTP for adaptive MFA, users must be enrolled with WhatsApp OTP as an authentication method. This means their phone number has previously been verified and can be trusted. The following steps demonstrate how to implement an enrollment flow using a Server SDK.

1. Initiate challenge

Call Initiate Challenge to send an OTP to a phone number.
const request = {
  verificationMethod: "WHATSAPP",
  action: "enrollWhatsApp",
  phoneNumber: "+64270000000",
  userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
  scope: "add:authenticators",
};

const response = await authsignal.challenge(request);

const challengeId = response.challengeId;
The add:authenticators scope is required to enroll a new WhatsApp authenticator for an existing user. This scope should only be used when the user is in an already authenticated state. For more information on using scopes safely refer to our documentation on authenticator binding.

2. Verify challenge

Once the user inputs the OTP code, call Verify Challenge to verify it.
const request = {
  challengeId: "3a991a14-690c-492b-a5e5-02b9056a4b7d",
  verificationCode: "123456",
};

const response = await authsignal.verify(request);

const isVerified = response.isVerified;

Update phone number

Scenario - Let users update their phone number while they’re authenticated, completing an OTP challenge to verify the new number.
The following steps demonstrate how to implement an update phone number flow using a Server SDK.

1. Initiate challenge

Call Initiate Challenge to send an OTP to the user’s new phone number.
const request = {
  verificationMethod: "WHATSAPP",
  action: "updatePhoneNumber",
  phoneNumber: "+64270000000",
  userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
  scope: "update:authenticators",
};

const response = await authsignal.challenge(request);

const challengeId = response.challengeId;
The update:authenticators scope is required to update a user’s existing WhatsApp authenticator to change the phone number. This scope should only be used when the user is in an already authenticated state. For more information on using scopes safely refer to our documentation on authenticator binding.

2. Verify challenge

Once the user inputs the OTP code, call Verify Challenge to verify it.
const request = {
  challengeId: "3a991a14-690c-492b-a5e5-02b9056a4b7d",
  verificationCode: "123456",
};

const response = await authsignal.verify(request);

const isVerified = response.isVerified;

Verified phone numbers

Scenario - Enroll or update a WhatsApp authenticator for a user when you’ve already verified their phone number in another system, so it can be used later as a method for adaptive MFA.
In some cases you may have already verified a user’s phone number using another system. This means the user can be enrolled without having to complete a WhatsApp OTP challenge.
const request = {
  userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
  attributes: {
    verificationMethod: "WHATSAPP",
    phoneNumber: "+64270000000",
  },
};

const response = authsignal.enrollVerifiedAuthenticator(request);
This same call can also be used to update a verified phone number to a new value which has also been verified externally.

Next steps

  • Pre-built UI - Rapidly deploy WhatsApp OTP challenges using our pre-built UI
  • Web SDK - Implement WhatsApp OTP challenges while building your own UI
  • Mobile SDK - Implement WhatsApp OTP challenges in native mobile apps
  • Adaptive MFA - Set up smart rules to trigger authentication based on risk
  • Passkeys - Offer the most secure and user-friendly passwordless authentication
I