Custom auth flow

You are currently viewing the AWS SDK for Mobile documentation which is a collection of low-level libraries. Use the Amplify libraries for all new app development. Learn more

Amazon Cognito User Pools supports customizing the authentication flow to enable custom challenge types, in addition to a password in order to verify the identity of users. These challenge types may include CAPTCHAs or dynamic challenge questions.

To define your challenges for custom authentication flow, you need to implement three Lambda triggers for Amazon Cognito.

For more information about working with Lambda Triggers for custom authentication challenges, please visit Amazon Cognito Developer Documentation.

Custom Authentication in Amplify

To initiate a custom authentication flow in your app, specify authenticationFlowType as CUSTOM_AUTH in the awsconfiguration.json file. Note that is not currently supported by the CLI and developers must manually update the awsconfiguration.json to specify authenticationFlowType as follows :

1{
2 "CognitoUserPool": {
3 "Default": {
4 "PoolId": "XX-XXXX-X_abcd1234",
5 "AppClientId": "XXXXXXXX",
6 "Region": "XX-XXXX-X"
7 }
8 },
9 "Auth": {
10 "Default": {
11 "authenticationFlowType": "CUSTOM_AUTH"
12 }
13 }
14}

Next, in the app code call signIn with a dummy password. Any custom challenges needs to be answered using the confirmSignIn method as follows:

1public void signIn() {
2 AWSMobileClient.getInstance().signIn(username, password, null, new Callback<SignInResult>() {
3 @Override
4 public void onResult(final SignInResult signInResult) {
5 runOnUiThread(new Runnable() {
6 @Override
7 public void run() {
8 Log.d("APP", "Sign-in callback state: " + signInResult.getSignInState());
9 switch (signInResult.getSignInState()) {
10 case DONE:
11 Log.d(TAG, "Sign-in done.");
12 break;
13 case SMS_MFA:
14 Log.d(TAG, "Please confirm sign-in with SMS.");
15 break;
16 case NEW_PASSWORD_REQUIRED:
17 Log.d(TAG, "Please confirm sign-in with new password.");
18 break;
19 case CUSTOM_CHALLENGE:
20 confirmSignIn();
21 break;
22 default:
23 Log.d(TAG, "Unsupported sign-in confirmation: " + signInResult.getSignInState());
24 break;
25 }
26 }
27 });
28 }
29
30 @Override
31 public void onError(Exception e) {
32 Log.e(TAG, "Sign-in error", e);
33 }
34 });
35}
36
37public void confirmSignIn() {
38 Map<String, String> res = new HashMap<String, String>();
39 res.put(CognitoServiceConstants.CHLG_RESP_ANSWER, "<CHALLENGE_RESPONSE>");
40 AWSMobileClient.getInstance().confirmSignIn(res, new Callback<SignInResult>() {
41 @Override
42 public void onResult(final SignInResult signInResult) {
43 runOnUiThread(new Runnable() {
44 @Override
45 public void run() {
46 Log.d(TAG, "Sign-in callback state: " + signInResult.getSignInState());
47 switch (signInResult.getSignInState()) {
48 case DONE:
49 Log.d(TAG, "Sign-in done.");
50 break;
51 case SMS_MFA:
52 Log.d(TAG, "Please confirm sign-in with SMS.");
53 break;
54 case NEW_PASSWORD_REQUIRED:
55 Log.d(TAG, "Please confirm sign-in with new password.");
56 break;
57 default:
58 Log.d(TAG, "Unsupported sign-in confirmation: " + signInResult.getSignInState());
59 break;
60 }
61 }
62 });
63 }
64
65 @Override
66 public void onError(Exception e) {
67 Log.e(TAG, "Confirm Custom auth Sign-in error", e);
68 }
69 });
70}

Lambda trigger setup

Amplify CLI can be used generate lambda triggers required by a custom authentication flow. See documentation for details. Amplify CLI creates a custom auth flow skeleton that you can manually edit. More information on each of the triggers can be found in Cognito documentation.

AWSMobileClient assumes that custom auth flows start with username and password. If you want a passwordless custom authentication flow, modify your Define Auth Challenge Lambda trigger to bypass the initial username/password verification and proceed to the custom challenge, as in the code below.

1exports.handler = (event, context) => {
2 if (event.request.session.length === 1 &&
3 event.request.session[0].challengeName === 'SRP_A') {
4 event.response.issueTokens = false;
5 event.response.failAuthentication = false;
6 event.response.challengeName = 'CUSTOM_CHALLENGE';
7 } else if (
8 event.request.session.length === 2 &&
9 event.request.session[1].challengeName === 'CUSTOM_CHALLENGE' &&
10 event.request.session[1].challengeResult === true
11 ) {
12 event.response.issueTokens = true;
13 event.response.failAuthentication = false;
14 } else {
15 event.response.issueTokens = false;
16 event.response.failAuthentication = true;
17 }
18 context.done(null, event);
19};