-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Added an example page for setting up custom-auth-flows #7947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 5 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
5c2b22d
added an example page for setting up custom-auth-flows
yuhengshs f838122
Update src/pages/[platform]/build-a-backend/functions/examples/custom…
yuhengshs 7807d13
add links in switching-authentication-flows
yuhengshs 55a5bc0
updated docs
yuhengshs 123e728
fixed wording issue for CUSTOM_AUTH challenge
yuhengshs fa3e3d4
Update index.mdx
yuhengshs 1317e10
updated callout
yuhengshs 4f4cd9c
added paragraph to what and why SRP
yuhengshs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
226 changes: 226 additions & 0 deletions
226
...pages/[platform]/build-a-backend/functions/examples/custom-auth-flows/index.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
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: | ||
yuhengshs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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; | ||
yuhengshs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.