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/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..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.
+
+
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..7b62b66f3d8
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx
@@ -0,0 +1,229 @@
+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
+ }
+ };
+}
+
+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)
+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) => {
+ // Check if this is the first authentication attempt
+ if (event.request.session.length === 0) {
+ // For the first attempt, we start with the custom challenge
+ 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 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 {
+ // 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;
+ }
+
+ 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) => {
+ // 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;
+ 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
+ ) {
+ // Second attempt: SRP_A was successful, move to PASSWORD_VERIFIER
+ 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
+ ) {
+ // Third attempt: PASSWORD_VERIFIER was successful, move to CUSTOM_CHALLENGE
+ 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
+ ) {
+ // 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;
+ }
+
+ 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.