Amplify has re-imagined the way frontend developers build fullstack applications. Develop and deploy without the hassle.

Page updated May 17, 2024

Custom auth flows

The Auth category can be configured to perform a custom authentication flow defined by you. The following guide shows how to setup a simple passwordless authentication flow.

Prerequisites

A Flutter application targeting Flutter SDK >= 3.3.0 with Amplify libraries integrated.

Amplify requires a minimum target platform for iOS (13.0), Android (API level 24), and macOS (10.15). Additional setup is required for some target platforms. Please see the platform setup for more details on platform specific setup.

Configure Auth

The custom auth flow can be configured manually.

Register a user

The flow as mentioned above requires a username and a valid email id as parameters to register a user. Invoke the following api to initiate a sign up flow.

Because authentication flows in Cognito can be switched via your configuration, it is still required that users register with a password.

Future<void> signUpCustomFlow() async {
try {
final userAttributes = <AuthUserAttributeKey, String>{
AuthUserAttributeKey.email: 'email@domain.com',
AuthUserAttributeKey.phoneNumber: '+15559101234',
// additional attributes as needed
};
final result = await Amplify.Auth.signUp(
username: 'myusername',
password: 'mysupersecurepassword',
options: SignUpOptions(userAttributes: userAttributes),
);
safePrint('Sign up result: $result');
} on AuthException catch (e) {
safePrint('Error signing up: ${e.message}');
}
}

The next step in the sign up flow is to confirm the user. A confirmation code will be sent to the email id provided during sign up. Enter the confirmation code received via email in the confirmSignUp call.

Future<void> confirmUser({
required String username,
required String confirmationCode,
}) async {
try {
final result = await Amplify.Auth.confirmSignUp(
username: username,
confirmationCode: confirmationCode,
);
// Check if further confirmations are needed or if
// the sign up is complete.
await _handleSignUpResult(result);
} on AuthException catch (e) {
safePrint('Error confirming user: ${e.message}');
}
}

Sign in a user

Implement a UI to get the username from the user. After the user enters the username you can start the sign in flow by calling the following method:

// Create state variables for the sign in status
var isSignedIn = false;
String? challengeHint;
Future<void> signInCustomFlow(String username) async {
try {
final result = await Amplify.Auth.signIn(username: username);
setState(() {
isSignedIn = result.isSignedIn;
// Get the publicChallengeParameters from your Create Auth Challenge Lambda
challengeHint = result.nextStep.additionalInfo['hint'];
});
} on AuthException catch (e) {
safePrint('Error signing in: ${e.message}');
}
}

Please note that you will be prevented from successfully calling signIn if a user has already signed in and a valid session is active. You must first call signOut to remove the original session.

Confirm sign in with custom challenge

To get a custom challenge from the user, create an appropriate UI for the user to submit the required value, and pass that value into the confirmSignin() API.

Future<void> confirmSignIn(String generatedNumber) async {
try {
final result = await Amplify.Auth.confirmSignIn(
/// Enter the random number generated by your Create Auth Challenge trigger
confirmationValue: generatedNumber,
);
safePrint('Sign in result: $result');
} on AuthException catch (e) {
safePrint('Error signing in: ${e.message}');
}
}

Once the user provides the correct response, they should be authenticated in your application.

Special Handling on ConfirmSignIn

During a confirmSignIn call, if failAuthentication: true is returned by the Lambda, the session of the request gets invalidated by Cognito, and a NotAuthorizedException is thrown. To recover, the user must initiate a new sign in by calling Amplify.Auth.signIn.

Exception: NotAuthorizedException with a message Invalid session for the user.

Custom authentication flow with password verification

The example in this documentation demonstrates the passwordless custom authentication flow. However, it is also possible to require that users supply a valid password as part of the custom authentication flow.

To require a valid password, you can alter the DefineAuthChallenge code to handle a PASSWORD_VERIFIER step:

exports.handler = async (event) => {
if (
event.request.session.length === 1 &&
event.request.session[0].challengeName === 'SRP_A'
) {
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
) {
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
) {
event.response.issueTokens = true;
event.response.failAuthentication = false;
} else {
event.response.issueTokens = false;
event.response.failAuthentication = true;
}
return event;
};