Using the AWS SDK with Authsignal's pre-built UI
Learn how to integrate Authsignal when using AWS Cognito and the AWS SDK.
This guide will demonstrate how to use the pre-built UI in redirect mode to present a passwordless challenge to the user on login.
It shows how to use the Authsignal Node SDK in your Cognito lambdas as well as the Authsignal Web SDK in your app.
The web app is a SPA which uses the following commands from the @aws-sdk/client-cognito-identity-provider
package to talk to Cognito:
- InitiateAuth
- RespondToAuthChallenge
- SignUp
Example code
You can find the full code example on Github.
User flow
The user enters their email to sign in.
The user is redirected to Authsignal to complete a challenge.
The user is redirected back to the client which then fetches an access token from Cognito.
Sequence diagram
Installation
Install the required npm modules with yarn (or npm):
yarn install
Running the SPA
VITE_COGNITO_CLIENT_ID=<ID_HERE> yarn run dev
User pool settings
For this example there are several important settings to configure when creating a Cognito User Pool:
Step 1
Choose Email
as the sign-in option.
Step 2
Choose No MFA
as the MFA option.
This can be implemented with Authsignal instead.
Step 3
Enable self-registration
so we can let users sign up directly from the SPA without going through a backend.
Step 4
Disable the Cognito Hosted UI
.
The SPA replaces this.
Step 5
Select Public client
for the app type. Also select `Don’t generate a client secret’.
The lambdas
The example repo contains four lambdas which can be deployed to your AWS environment.
Once deployed, these lambdas can be connected to your Cognito user pool:
Create Auth Challenge lambda
This lambda uses the Authsignal Node.js SDK to return a short-lived token back to the app which can be passed to the Authsignal Web SDK to launch the Authsignal pre-built UI in a popup:
export const handler: CreateAuthChallengeTriggerHandler = async (event) => {
const userId = event.request.userAttributes.sub;
const email = event.request.userAttributes.email;
// This can be any value which defines your login action
const action = "cognitoAuth";
const { url } = await authsignal.track({
action,
userId,
email,
});
event.response.publicChallengeParameters = { url };
return event;
};
Verify Auth Challenge Response lambda
This lambda takes the result token returned by the Authsignal Web SDK and passes it to the Authsignal Node.js SDK to validate the result of the challenge:
export const handler: VerifyAuthChallengeResponseTriggerHandler = async (
event
) => {
const token = event.request.challengeAnswer;
const userId = event.request.userAttributes.sub;
// This must be the same value used in the previous step
const action = "cognitoAuth";
const { state } = await authsignal.validateChallenge({
action,
userId,
token,
});
event.response.answerCorrect = state === "CHALLENGE_SUCCEEDED";
return event;
};
Important API calls
The SPA makes use of 3 Cognito API calls via the AWS SDK:
InitiateAuth
This API call is responsible for starting the authentication process.
This API is passed the username and CUSTOM_AUTH
as the authentication flow and returns a URL to Authsignal’s pre-built UI as well as a Cognito session token.
The SPA then redirects to the Authsignal URL which will allow the user to complete a passwordless authentication challenge.
After the challenge is completed the pre-built UI will redirect back to the SPA’s /callback
endpoint with a token in the query string.
ResponseToAuthChallenge
This API call is responsible for completing the authentication flow. This API is passed multiple parameters, most importantly the session string, and the Authsignal token as the ANSWER parameter. The return values include both a cognito access and refresh token.
SignUp
This API call is responsible for adding a user to the user pool. In this example we call SignUp if the sign in flow fails. This API is passed a username and password. Because we’ve configured a passwordless authentication flow the user doesn’t need to be aware of the password, so we generate a secure random password in the client and use that.
Next steps
Was this page helpful?