Custom auth flow
Amazon Cognito User Pools supports customizing the authentication flow to enable custom challenge types. These challenge types may include CAPTCHAs or dynamic challenge questions. To define your challenges you need to implement three Lambda triggers.
For more information about working with Lambda Triggers for custom authentication challenges visit Amazon Cognito Developer Documentation.
Custom Authentication in Amplify
To enable a custom authentication flow update your awsconfiguration.json
file and set authenticationFlowType
to CUSTOM_AUTH
.
{ "CognitoUserPool": { "Default": { "PoolId": "XX-XXXX-X_abcd1234", "AppClientId": "XXXXXXXX", "Region": "XX-XXXX-X" } }, "Auth": { "Default": { "authenticationFlowType": "CUSTOM_AUTH" } }}
In your app code call signIn
with a dummy password. Custom challenges need to be answered using the confirmSignIn
method:
AWSMobileClient.default().signIn( username: username, password: "dummyPassword") { (signInResult, error) in if let signInResult = signInResult { if (signInResult.signInState == .customChallenge) { // Retrieve challenge details } }}
Get the challenge details from the user and then call confirmSignIn
AWSMobileClient.default().confirmSignIn( challengeResponse: "<Challenge Response>", completionHandler: { (signInResult, error) in if let error = error { print("\(error.localizedDescription)") } else if let signInResult = signInResult { switch (signInResult.signInState) { case .signedIn: print("User is signed in.") default: print("\(signInResult.signInState.rawValue)") } } })
Lambda Trigger Setup
The Amplify CLI can be used to generate triggers required by a custom authentication flow. See the CLI Documentation for details. The CLI will create a custom auth flow skeleton that you can manually edit.
More information on available triggers can be found in the Cognito documentation.
AWSMobileClient
assumes the custom auth flow starts with username and password. If you want a passwordless authentication flow, modify your Define Auth Challenge Lambda trigger to bypass the initial username/password verification and proceed to the custom challenge:
exports.handler = (event, context) => { if ( event.request.session.length === 1 && event.request.session[0].challengeName === 'SRP_A' ) { event.response.issueTokens = false; event.response.failAuthentication = false; event.response.challengeName = 'CUSTOM_CHALLENGE'; } else if ( event.request.session.length === 2 && event.request.session[1].challengeName === 'CUSTOM_CHALLENGE' && event.request.session[1].challengeResult === true ) { event.response.issueTokens = true; event.response.failAuthentication = false; } else { event.response.issueTokens = false; event.response.failAuthentication = true; } context.done(null, event);};