From 5c2b22dd9977c1efefa688ce0ff723d1ddfb42d0 Mon Sep 17 00:00:00 2001 From: yuhengshs Date: Fri, 6 Sep 2024 10:51:33 -0700 Subject: [PATCH 1/8] added an example page for setting up custom-auth-flows --- src/directory/directory.mjs | 3 + .../examples/custom-auth-flows/index.mdx | 215 ++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx diff --git a/src/directory/directory.mjs b/src/directory/directory.mjs index d8bcb643a59..a5be302bf9e 100644 --- a/src/directory/directory.mjs +++ b/src/directory/directory.mjs @@ -417,6 +417,9 @@ export const directory = { }, { path: 'src/pages/[platform]/build-a-backend/functions/examples/s3-upload-confirmation/index.mdx' + }, + { + path: 'src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx' } ] }, diff --git a/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx b/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx new file mode 100644 index 00000000000..820439ac2d1 --- /dev/null +++ b/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx @@ -0,0 +1,215 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Custom Auth Challenge', + description: + 'Leverage Custom Auth with and without SRP, Allowing for a series of challenge and response cycles that can be customized to meet different requirements during sign in.', + platforms: [ + 'android', + 'angular', + 'flutter', + 'javascript', + 'nextjs', + 'react', + 'react-native', + 'swift', + 'vue' + ] +}; + +export function getStaticPaths() { + return getCustomStaticPath(meta.platforms); +} + +export function getStaticProps() { + return { + props: { + meta + } + }; +} + +You can use `defineAuth` and `defineFunction` to create an auth experience that uses `CUSTOM_WITH_SRP` and `CUSTOM_WITHOUT_SRP`. This can be accomplished by leveraging [Amazon Cognito's feature to define a custom auth challenge](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#Custom-authentication-flow-and-challenges) and 3 triggers: + +1. [Create auth challenge](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-create-auth-challenge.html) +2. [Define auth challenge](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-define-auth-challenge.html) +3. [Verify auth challenge response](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-verify-auth-challenge-response.html) + +To get started, install the `aws-lambda` package, which is used to define the handler type. + +```bash title="Terminal" showLineNumbers={false} +npm add --save-dev @types/aws-lambda +``` + +## Create auth challenge trigger + +To get started, create the first of the three triggers, `create-auth-challenge`. This is the trigger responsible for creating the reCAPTCHA challenge after a password is verified. + +```ts title="amplify/auth/create-auth-challenge/resource.ts" +import { defineFunction } from "@aws-amplify/backend" + +export const createAuthChallenge = defineFunction({ + name: "create-auth-challenge", +}) +``` + +After creating the resource file, create the handler with the following contents: + +```ts title="amplify/auth/create-auth-challenge/handler.ts" +import type { CreateAuthChallengeTriggerHandler } from "aws-lambda"; + +export const handler: CreateAuthChallengeTriggerHandler = async (event) => { + if (event.request.challengeName === "CUSTOM_CHALLENGE") { + // Generate a random code for the custom challenge + const challengeCode = "123456"; + + event.response.challengeMetadata = "TOKEN_CHECK"; + + event.response.publicChallengeParameters = { + trigger: "true", + code: challengeCode, + }; + + event.response.privateChallengeParameters = { trigger: "true" }; + event.response.privateChallengeParameters.answer = challengeCode; + } + return event; +}; +``` + +## Define auth challenge trigger + +Next, you will want to create the trigger responsible for _defining_ the auth challenge flow, `define-auth-challenge`. + +```ts title="amplify/auth/define-auth-challenge/resource.ts" +import { defineFunction } from "@aws-amplify/backend" + +export const defineAuthChallenge = defineFunction({ + name: "define-auth-challenge", +}) +``` + +After creating the resource file, create the handler with the following contents if you are using `CUSTOM_WITHOUT_SRP`: + +```ts title="amplify/auth/define-auth-challenge/handler.ts" +import type { DefineAuthChallengeTriggerHandler } from "aws-lambda" + +export const handler: DefineAuthChallengeTriggerHandler = async (event) => { + if (event.request.session.length === 0) { + // If it's the first auth stage + event.response.issueTokens = false; + event.response.failAuthentication = false; + event.response.challengeName = "CUSTOM_CHALLENGE"; + } else if ( + event.request.session.length === 1 && + event.request.session[0].challengeName === "CUSTOM_CHALLENGE" && + event.request.session[0].challengeResult === true + ) { + // If CUSTOM_CHALLENGE is passed + event.response.issueTokens = true; + event.response.failAuthentication = false; + } else { + // Fail auth if we don't have the expected challenge results + event.response.issueTokens = false; + event.response.failAuthentication = true; + } + + return event; +}; +``` + +Or if you are using `CUSTOM_WITH_SRP`: + +```ts title="amplify/auth/define-auth-challenge/handler.ts" +import type { DefineAuthChallengeTriggerHandler } from "aws-lambda" + +export const handler: DefineAuthChallengeTriggerHandler = async (event) => { + if (event.request.session.length === 0) { + event.response.issueTokens = false; + event.response.failAuthentication = false; + event.response.challengeName = "SRP_A"; + } else if ( + event.request.session.length === 1 && + event.request.session[0].challengeName === "SRP_A" && + event.request.session[0].challengeResult === true + ) { + event.response.issueTokens = false; + event.response.failAuthentication = false; + event.response.challengeName = "PASSWORD_VERIFIER"; + } else if ( + event.request.session.length === 2 && + event.request.session[1].challengeName === "PASSWORD_VERIFIER" && + event.request.session[1].challengeResult === true + ) { + event.response.issueTokens = false; + event.response.failAuthentication = false; + event.response.challengeName = "CUSTOM_CHALLENGE"; + } else if ( + event.request.session.length === 3 && + event.request.session[2].challengeName === "CUSTOM_CHALLENGE" && + event.request.session[2].challengeResult === true + ) { + event.response.issueTokens = true; + event.response.failAuthentication = false; + } else { + event.response.issueTokens = false; + event.response.failAuthentication = true; + } + + return event; +}; +``` + +## Verify auth challenge response trigger + +Lastly, create the trigger responsible for _verifying_ the challenge response. For the purpose of this example, the verification check will always return true. + +```ts title="amplify/auth/verify-auth-challenge-response/resource.ts" +import { defineFunction, secret } from "@aws-amplify/backend" + +export const verifyAuthChallengeResponse = defineFunction({ + name: "verify-auth-challenge-response", +}) +``` + +After creating the resource file, create the handler with the following contents: + +```ts title="amplify/auth/verify-auth-challenge-response/handler.ts" +import type { VerifyAuthChallengeResponseTriggerHandler } from "aws-lambda" + +export const handler: VerifyAuthChallengeResponseTriggerHandler = async ( + event +) => { + event.response.answerCorrect = true; + return event; +}; + +``` + +## Configure auth resource + +Finally, import and set the three triggers on your auth resource: + +```ts title="amplify/auth/resource.ts" +import { defineAuth } from "@aws-amplify/backend" +import { createAuthChallenge } from "./create-auth-challenge/resource" +import { defineAuthChallenge } from "./define-auth-challenge/resource" +import { verifyAuthChallengeResponse } from "./verify-auth-challenge-response/resource" + +/** + * Define and configure your auth resource + * @see https://docs.amplify.aws/gen2/build-a-backend/auth + */ +export const auth = defineAuth({ + loginWith: { + email: true, + }, + triggers: { + createAuthChallenge, + defineAuthChallenge, + verifyAuthChallengeResponse, + }, +}) +``` + +After deploying the changes, whenever a user attempts to sign in with `CUSTOM_WITH_SRP` or `CUSTOM_WITHOUT_SRP`, the lambda challenges will be triggered. From f838122f93839ee3e8f0cdd03a3a50d40e460c05 Mon Sep 17 00:00:00 2001 From: yuhengshs <94558971+yuhengshs@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:29:25 -0700 Subject: [PATCH 2/8] Update src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx Co-authored-by: josef --- .../functions/examples/custom-auth-flows/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx b/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx index 820439ac2d1..96c51f6a622 100644 --- a/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx @@ -3,7 +3,7 @@ import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; export const meta = { title: 'Custom Auth Challenge', description: - 'Leverage Custom Auth with and without SRP, Allowing for a series of challenge and response cycles that can be customized to meet different requirements during sign in.', + 'Leverage Custom Auth with and without SRP, allowing for a series of challenge and response cycles that can be customized to meet different requirements during sign in.', platforms: [ 'android', 'angular', From 7807d13dc78cc490213272b9f08cf8e33962297e Mon Sep 17 00:00:00 2001 From: yuhengshs Date: Fri, 6 Sep 2024 12:03:55 -0700 Subject: [PATCH 3/8] add links in switching-authentication-flows --- .../switching-authentication-flows/index.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index e18fd879ad7..1c9f278483b 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -189,10 +189,12 @@ if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') { await confirmSignIn({ challengeResponse }); } ``` +To create a CUSTOM_AUTH challenge with a Lambda Trigger, please visit [AWS Amplify Google reCAPTCHA challenge example](/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/) for detailed examples. + ### CAPTCHA authentication -To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify Google reCAPTCHA challenge example](/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/) for detailed examples. +To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for set up instructions. From 55a5bc0d891929a19197a6828567d39901e8ce0d Mon Sep 17 00:00:00 2001 From: yuhengshs Date: Mon, 9 Sep 2024 10:41:21 -0700 Subject: [PATCH 4/8] updated docs --- .../switching-authentication-flows/index.mdx | 4 ++-- .../examples/custom-auth-flows/index.mdx | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index 1c9f278483b..060afeaab55 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -189,12 +189,12 @@ if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') { await confirmSignIn({ challengeResponse }); } ``` -To create a CUSTOM_AUTH challenge with a Lambda Trigger, please visit [AWS Amplify Google reCAPTCHA challenge example](/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/) for detailed examples. +To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for set up instructions. ### CAPTCHA authentication -To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for set up instructions. +To create a CUSTOM_AUTH challenge with a Lambda Trigger, please visit [AWS Amplify Google reCAPTCHA challenge example](/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/) for detailed examples. diff --git a/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx b/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx index 96c51f6a622..0f1a39e560b 100644 --- a/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx @@ -95,8 +95,9 @@ After creating the resource file, create the handler with the following contents import type { DefineAuthChallengeTriggerHandler } from "aws-lambda" export const handler: DefineAuthChallengeTriggerHandler = async (event) => { + // Check if this is the first authentication attempt if (event.request.session.length === 0) { - // If it's the first auth stage + // For the first attempt, we start with the custom challenge event.response.issueTokens = false; event.response.failAuthentication = false; event.response.challengeName = "CUSTOM_CHALLENGE"; @@ -105,11 +106,15 @@ export const handler: DefineAuthChallengeTriggerHandler = async (event) => { event.request.session[0].challengeName === "CUSTOM_CHALLENGE" && event.request.session[0].challengeResult === true ) { - // If CUSTOM_CHALLENGE is passed + // If this is the second attempt (session length 1), + // it was a CUSTOM_CHALLENGE, and the result was successful event.response.issueTokens = true; event.response.failAuthentication = false; } else { - // Fail auth if we don't have the expected challenge results + // If we reach here, it means either: + // 1. The custom challenge failed + // 2. We've gone through more attempts than expected + // In either case, we fail the authentication event.response.issueTokens = false; event.response.failAuthentication = true; } @@ -124,6 +129,7 @@ Or if you are using `CUSTOM_WITH_SRP`: import type { DefineAuthChallengeTriggerHandler } from "aws-lambda" export const handler: DefineAuthChallengeTriggerHandler = async (event) => { + // First attempt: Start with SRP_A (Secure Remote Password protocol, step A) if (event.request.session.length === 0) { event.response.issueTokens = false; event.response.failAuthentication = false; @@ -133,6 +139,7 @@ export const handler: DefineAuthChallengeTriggerHandler = async (event) => { event.request.session[0].challengeName === "SRP_A" && event.request.session[0].challengeResult === true ) { + // Second attempt: SRP_A was successful, move to PASSWORD_VERIFIER event.response.issueTokens = false; event.response.failAuthentication = false; event.response.challengeName = "PASSWORD_VERIFIER"; @@ -141,6 +148,7 @@ export const handler: DefineAuthChallengeTriggerHandler = async (event) => { event.request.session[1].challengeName === "PASSWORD_VERIFIER" && event.request.session[1].challengeResult === true ) { + // Third attempt: PASSWORD_VERIFIER was successful, move to CUSTOM_CHALLENGE event.response.issueTokens = false; event.response.failAuthentication = false; event.response.challengeName = "CUSTOM_CHALLENGE"; @@ -149,9 +157,12 @@ export const handler: DefineAuthChallengeTriggerHandler = async (event) => { event.request.session[2].challengeName === "CUSTOM_CHALLENGE" && event.request.session[2].challengeResult === true ) { + // Fourth attempt: CUSTOM_CHALLENGE was successful, authentication complete event.response.issueTokens = true; event.response.failAuthentication = false; } else { + // If we reach here, it means one of the challenges failed or + // we've gone through more attempts than expected event.response.issueTokens = false; event.response.failAuthentication = true; } @@ -212,4 +223,4 @@ export const auth = defineAuth({ }) ``` -After deploying the changes, whenever a user attempts to sign in with `CUSTOM_WITH_SRP` or `CUSTOM_WITHOUT_SRP`, the lambda challenges will be triggered. +After deploying the changes, whenever a user attempts to sign in with `CUSTOM_WITH_SRP` or `CUSTOM_WITHOUT_SRP`, the Lambda challenges will be triggered. From 123e728d9fa7153c85d2ebf7a026b6d77f562202 Mon Sep 17 00:00:00 2001 From: yuhengshs Date: Mon, 9 Sep 2024 10:44:13 -0700 Subject: [PATCH 5/8] fixed wording issue for CUSTOM_AUTH challenge --- .../switching-authentication-flows/index.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index 060afeaab55..06fb9c2b54a 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -189,12 +189,12 @@ if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') { await confirmSignIn({ challengeResponse }); } ``` -To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for set up instructions. +To create a CUSTOM_AUTH challenge with a Lambda Trigger, please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for set up instructions. ### CAPTCHA authentication -To create a CUSTOM_AUTH challenge with a Lambda Trigger, please visit [AWS Amplify Google reCAPTCHA challenge example](/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/) for detailed examples. +To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify Google reCAPTCHA challenge example](/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/) for detailed examples. From fa3e3d460da14b5257c58522fb4fd7d28630e7b7 Mon Sep 17 00:00:00 2001 From: yuhengshs <94558971+yuhengshs@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:50:40 -0700 Subject: [PATCH 6/8] Update index.mdx Co-authored-by: josef --- .../switching-authentication-flows/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index 06fb9c2b54a..4c6b92256e5 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -189,8 +189,8 @@ if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') { await confirmSignIn({ challengeResponse }); } ``` -To create a CUSTOM_AUTH challenge with a Lambda Trigger, please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for set up instructions. +To create a CUSTOM_AUTH challenge with a Lambda Trigger, please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for setup instructions. ### CAPTCHA authentication From 1317e10cd9a200a22b0e4dac925fbfc7cef7beed Mon Sep 17 00:00:00 2001 From: yuhengshs Date: Tue, 10 Sep 2024 13:48:46 -0700 Subject: [PATCH 7/8] updated callout --- .../switching-authentication-flows/index.mdx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index 4c6b92256e5..dbddf87f4bb 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -160,7 +160,11 @@ in addition to a password in order to verify the identity of users. These challe or dynamic challenge questions. The `CUSTOM_WITH_SRP` flow requires a password when calling `signIn`. Both of these flows map to the `CUSTOM_AUTH` flow in Cognito. -To define your challenges for custom authentication flow, you need to implement three Lambda triggers for Amazon Cognito. + + +To define your challenges for custom authentication flow, you need to implement three Lambda triggers for Amazon Cognito. Please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for set up instructions. + + @@ -190,8 +194,6 @@ if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') { } ``` -To create a CUSTOM_AUTH challenge with a Lambda Trigger, please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for setup instructions. - ### CAPTCHA authentication To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify Google reCAPTCHA challenge example](/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/) for detailed examples. From 4f4cd9cd854da96960372fa378417b4dc5820f4f Mon Sep 17 00:00:00 2001 From: yuhengshs Date: Wed, 11 Sep 2024 14:29:59 -0700 Subject: [PATCH 8/8] added paragraph to what and why SRP --- .../functions/examples/custom-auth-flows/index.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx b/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx index 0f1a39e560b..7b62b66f3d8 100644 --- a/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx @@ -29,6 +29,9 @@ export function getStaticProps() { }; } +Secure Remote Password (SRP) is a cryptographic protocol enabling password-based authentication without transmitting the password over the network. In Amazon Cognito custom authentication flows, CUSTOM_WITH_SRP incorporates SRP steps for enhanced security, while CUSTOM_WITHOUT_SRP bypasses these for a simpler process. The choice between them depends on your application's security needs and performance requirements. +This guide demonstrates how to implement both types of custom authentication flows using AWS Amplify with Lambda triggers. + You can use `defineAuth` and `defineFunction` to create an auth experience that uses `CUSTOM_WITH_SRP` and `CUSTOM_WITHOUT_SRP`. This can be accomplished by leveraging [Amazon Cognito's feature to define a custom auth challenge](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#Custom-authentication-flow-and-challenges) and 3 triggers: 1. [Create auth challenge](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-create-auth-challenge.html)