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](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html).

## 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 : 

```json
{
  "CognitoUserPool": {
    "Default": {
      "PoolId": "XX-XXXX-X_abcd1234",
      "AppClientId": "XXXXXXXX",
      "Region": "XX-XXXX-X"
    }
  },
  "Auth": {
    "Default": {
      "authenticationFlowType": "CUSTOM_AUTH"
    }
  }
}
```

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

```java
public void signIn() {
    AWSMobileClient.getInstance().signIn(username, password, null, new Callback<SignInResult>() {
        @Override
        public void onResult(final SignInResult signInResult) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("APP", "Sign-in callback state: " + signInResult.getSignInState());
                    switch (signInResult.getSignInState()) {
                        case DONE:
                            Log.d(TAG, "Sign-in done.");
                            break;
                        case SMS_MFA:
                            Log.d(TAG, "Please confirm sign-in with SMS.");
                            break;
                        case NEW_PASSWORD_REQUIRED:
                            Log.d(TAG, "Please confirm sign-in with new password.");
                            break;
                        case CUSTOM_CHALLENGE:
                            confirmSignIn();
                            break;
                        default:
                            Log.d(TAG, "Unsupported sign-in confirmation: " + signInResult.getSignInState());
                            break;
                    }
                }
            });
        }

        @Override
        public void onError(Exception e) {
            Log.e(TAG, "Sign-in error", e);
        }
    });
}

public void confirmSignIn() {
    Map<String, String> res = new HashMap<String, String>();
    res.put(CognitoServiceConstants.CHLG_RESP_ANSWER, "<CHALLENGE_RESPONSE>");
    AWSMobileClient.getInstance().confirmSignIn(res, new Callback<SignInResult>() {
        @Override
        public void onResult(final SignInResult signInResult) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG, "Sign-in callback state: " + signInResult.getSignInState());
                    switch (signInResult.getSignInState()) {
                        case DONE:
                            Log.d(TAG, "Sign-in done.");
                            break;
                        case SMS_MFA:
                            Log.d(TAG, "Please confirm sign-in with SMS.");
                            break;
                        case NEW_PASSWORD_REQUIRED:
                            Log.d(TAG, "Please confirm sign-in with new password.");
                            break;
                        default:
                            Log.d(TAG, "Unsupported sign-in confirmation: " + signInResult.getSignInState());
                            break;
                    }
                }
            });
        }

        @Override
        public void onError(Exception e) {
            Log.e(TAG, "Confirm Custom auth Sign-in error", e);
        }
    });
}
```

### Lambda trigger setup

Amplify CLI can be used generate lambda triggers required by a custom authentication flow. See [documentation](/cli/usage/lambda-triggers) 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](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html).

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

```javascript
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);
};
``` 
