In the previous guide we demonstrated how to enroll the user’s first authenticator as part of a combined sign-up/sign-in flow.

This guide will cover the implementation steps for letting users enroll and manage multiple different authentication methods when integrating Authsignal with Amazon Cognito.

Github example code

Enrolling more authenticators

Once the user has enrolled their first authentication method and has signed in, we want to give them the option to enroll more authentication methods.

As an example, we’ll demonstrate how to let users enroll email OTP as a second authentication method - but the implementation approach will be similar for all authentications methods.

While authentication methods can be enrolled in any sequence, it’s recommended to only let users enroll passkeys after they’ve first enrolled a method like email or SMS OTP, so users always have a fallback option in cases where their passkey isn’t available.

Lambda integration

To authorize binding the new authentication method to the user, we will create an authenticated API endpoint which our app can call once they’ve signed in.

This endpoint will use a JWT Authorizer to authenticate using the Cognito access token. It will return a short-lived Authsignal token which we’ll use in the following step.

export const handler = async (event: APIGatewayProxyEventV2WithJWTAuthorizer) => {
  const { token: authsignalToken } = await authsignal.track({
    userId: event.requestContext.authorizer.jwt.claims.sub,
    action: "addAuthenticator",
    attributes: {
      scope: "add:authenticators",
    },
  });

  return {
    authsignalToken,
  };
};

App integration

  1. Call our endpoint to obtain the Authsignal token.
// Replace with your API endpoint URL
const apiEndpointUrl = "https://abcd1234.execute-api.us-west-1.amazonaws.com/authenticators";

const authsignalToken = await fetch(apiEndpointUrl, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${cognitoAccessToken}`,
  },
})
  .then((res) => res.json())
  .then((json) => json.authsignalToken);
  1. Enroll the email OTP authenticator using a Client SDK.
// 1. Set the token obtained from your API endpoint
authsignal.setToken(token);

// 2. Send the user an OTP code via email
await authsignal.email.enroll({ email: "user@example.com" });

// 3. Verify the code inputted by the user to complete the enrollment
const response = await authsignal.email.verify({ code: "123456" });

For more information on how to use other authentication methods refer to our Web SDK and Mobile SDK documentation.

Removing authenticators

The Authsignal Server SDK can be used within your authenticated API endpoint to get the user’s currently enrolled authenticators and to remove an authenticator by its ID.

The example code below demonstrates how to remove the user’s email OTP authenticator by using the Authsignal Server SDK inside an API endpoint which is authenticated using a JWT authorizer.

export const handler = async (event: APIGatewayProxyEventV2WithJWTAuthorizer) => {
  const userId = event.requestContext.authorizer.jwt.claims.sub;

  // Get the user's currently enrolled authenticators
  const authenticators = await authsignal.getAuthenticators({ userId });

  // Find the email OTP authenticator ID
  const emailOtpAuthenticator = authenticators.find((a) => a.verificationMethod === "EMAIL_OTP");

  // Remove the email OTP authenticator
  await authsignal.deleteAuthenticator({
    userId,
    userAuthenticatorId: emailOtpAuthenticator.userAuthenticatorId,
  });
};

For more information refer to our Server SDK documentation.

Next steps