- 
                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.