This example shows how to integrate Authsignal with AWS Cognito in a simple React web app.
If you're looking for a similar example but for React Native, you can find one here.
yarn install
Rename the example env config file from .env.example
to .env
then update it with values for your Authsignal tenant and Cognito user pool.
This 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:
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;
const { url } = await authsignal.track({
action: "cognitoAuth",
userId,
email,
});
event.response.publicChallengeParameters = { url };
return event;
};
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 userId = event.request.userAttributes.sub;
const token = event.request.challengeAnswer;
const { state } = await authsignal.validateChallenge({ userId, token });
event.response.answerCorrect = state === "CHALLENGE_SUCCEEDED";
return event;
};
These lambdas don't have any interesting interaction with Authsignal but are required to get things working end-to-end. You can find out more info about what they do in this AWS blog post.
Run the app with the following command:
yarn dev
The example app only has a "Sign in" page - as part of this flow we try to create the user in Cognito first and if they already exist we simply ignore the error and continue.
try {
const signUpInput: SignUpInput = {
username: email,
password: Math.random().toString(36).slice(-16) + "X", // Dummy value - never used
options: {
userAttributes: {
email,
},
},
};
await signUp(signUpInput);
} catch (ex) {
if (ex instanceof Error && ex.name !== "UsernameExistsException") {
throw ex;
}
}
Similar to the example in this AWS blog post, a dummy password is randomly generated because Amplify requires one when signing up, but it won't actually be used.
We call the Amplify signIn
method, which invokes the Create Auth Challenge lambda and returns a URL for the pre-built UI.
We pass this URL to the Authsignal Web SDK, which opens it in a popup or modal to present the challenge.
Once the user has completed the challenge, the Authsignal Web SDK returns a token.
We pass this token back to the Amplify confirmSignIn
method, which invokes the Verify Auth Challenge Response lambda.
const signInInput = {
username: email,
options: {
authFlowType: "CUSTOM_WITHOUT_SRP",
},
};
const { nextStep } = await signIn(signInInput);
const url = nextStep.additionalInfo.url;
const { token } = await authsignal.launch(url, { mode: "popup" });
await confirmSignIn({ challengeResponse: token });