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

  • An Android application targeting at least Android SDK API level 24 with Amplify libraries integrated

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.

AuthSignUpOptions options = AuthSignUpOptions.builder()
.userAttribute(AuthUserAttributeKey.email(), "my@email.com")
.build();
Amplify.Auth.signUp("username", "Password123", options,
result -> Log.i("AuthQuickStart", "Result: " + result.toString()),
error -> Log.e("AuthQuickStart", "Sign up failed", error)
);
val options = AuthSignUpOptions.builder()
.userAttribute(AuthUserAttributeKey.email(), "my@email.com")
.build()
Amplify.Auth.signUp("username", "Password123", options,
{ Log.i("AuthQuickStart", "Sign up succeeded: $it") },
{ Log.e ("AuthQuickStart", "Sign up failed", it) }
)
val options = AuthSignUpOptions.builder()
.userAttribute(AuthUserAttributeKey.email(), "my@email.com")
.build()
try {
val result = Amplify.Auth.signUp("username", "Password123", options)
Log.i("AuthQuickStart", "Result: $result")
} catch (error: AuthException) {
Log.e("AuthQuickStart", "Sign up failed", error)
}
RxAmplify.Auth.signUp(
"username",
"Password123",
AuthSignUpOptions.builder().userAttribute(AuthUserAttributeKey.email(), "my@email.com").build())
.subscribe(
result -> Log.i("AuthQuickStart", "Result: " + result.toString()),
error -> Log.e("AuthQuickStart", "Sign up failed", error)
);

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.

Amplify.Auth.confirmSignUp(
"username",
"the code you received via email",
result -> Log.i("AuthQuickstart", result.isSignUpComplete() ? "Confirm signUp succeeded" : "Confirm sign up not complete"),
error -> Log.e("AuthQuickstart", error.toString())
);
Amplify.Auth.confirmSignUp(
"username", "the code you received via email",
{ result ->
if (result.isSignUpComplete) {
Log.i("AuthQuickstart", "Confirm signUp succeeded")
} else {
Log.i("AuthQuickstart","Confirm sign up not complete")
}
},
{ Log.e("AuthQuickstart", "Failed to confirm sign up", it) }
)
try {
val code = "code you received via email"
val result = Amplify.Auth.confirmSignUp("username", code)
if (result.isSignUpComplete) {
Log.i("AuthQuickstart", "Signup confirmed")
} else {
Log.i("AuthQuickstart", "Signup confirmation not yet complete")
}
} catch (error: AuthException) {
Log.e("AuthQuickstart", "Failed to confirm signup", error)
}
RxAmplify.Auth.confirmSignUp("username", "the code you received via email")
.subscribe(
result -> Log.i("AuthQuickstart", result.isSignUpComplete() ? "Confirm signUp succeeded" : "Confirm sign up not complete"),
error -> Log.e("AuthQuickstart", error.toString())
);

You will know the sign up flow is complete if you see the following in your console window:

Confirm signUp succeeded

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:

AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
.authFlowType(AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP)
.build();
Amplify.Auth.signIn(
"username",
"password",
options,
result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
error -> Log.e("AuthQuickstart", error.toString())
);
val options = AWSCognitoAuthSignInOptions.builder()
.authFlowType(AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP)
.build()
Amplify.Auth.signIn(
"username",
"password",
options,
{ result ->
if (result.isSignedIn) {
Log.i("AuthQuickstart", "Sign in succeeded")
} else {
Log.i("AuthQuickstart", "Sign in not complete")
}
},
{ Log.e("AuthQuickstart", "Failed to sign in", it) }
)
val options = AWSCognitoAuthSignInOptions.builder()
.authFlowType(AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP)
.build()
try {
val result = Amplify.Auth.signIn("username", "password", options)
if (result.isSignedIn) {
Log.i("AuthQuickstart", "Sign in succeeded")
} else {
Log.e("AuthQuickstart", "Sign in not complete")
}
} catch (error: AuthException) {
Log.e("AuthQuickstart", "Sign in failed", error)
}
AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
.authFlowType(AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP)
.build();
RxAmplify.Auth.signIn("username", "password", options)
.subscribe(
result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
error -> Log.e("AuthQuickstart", error.toString())
);

Since this is a custom authentication flow with a challenge, the result of the signin process has a next step .confirmSignInWithCustomChallenge. Implement a UI to allow the user to enter the custom challenge.

Confirm sign in with custom challenge

Get the custom challenge (1234 in this case) from the user and pass it to the confirmSignin() api.

Amplify.Auth.confirmSignIn(
"confirmation",
result -> Log.i("AuthQuickstart", "Confirm sign in succeeded: " + result.toString()),
error -> Log.e("AuthQuickstart", "Failed to confirm sign in", error)
);
Amplify.Auth.confirmSignIn("confirmation",
{ Log.i("AuthQuickstart", "Confirm sign in succeeded: $it") },
{ Log.e("AuthQuickstart", "Failed to confirm sign in", it) }
)
try {
val result = Amplify.Auth.confirmSignIn("confirmation")
Log.i("AuthQuickstart", "Confirm sign in succeeded: $result")
} catch (error: AuthException) {
Log.e("AuthQuickstart", "Failed to confirm signin", error)
}
RxAmplify.Auth.confirmSignIn("confirmation")
.subscribe(
result -> Log.i("AuthQuickstart", result.toString()),
error -> Log.e("AuthQuickstart", error.toString())
);

You will know the sign in flow is complete if you see the following in your console window:

Confirm sign in succeeded

Lambda Trigger Setup

AWS Amplify now supports creating functions as part of the AWS Amplify. For more information on the Functions and how to start with them check out Functions documentation. In addition, more information on available triggers can be found in the Cognito documentation.

Custom Auth Flow with Secure Remote Password (SRP)

Cognito User Pool allows to start the custom authentication flow with SRP as the first step. If you would like to use this flow, setup Define Auth Lambda trigger to handle SRP_A as the first challenge as shown below:

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 = '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;
}
context.done(null, event);
};

If your lambda is setup to start with SRP as the first step, make sure to initiate the signIn process with customWithSRP as the authentication flow:

AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
.authFlowType(AuthFlowType.CUSTOM_AUTH_WITH_SRP)
.build();
Amplify.Auth.signIn(
"username",
"password",
options,
result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
error -> Log.e("AuthQuickstart", error.toString())
);
val options = AWSCognitoAuthSignInOptions.builder()
.authFlowType(AuthFlowType.CUSTOM_AUTH_WITH_SRP)
.build()
Amplify.Auth.signIn(
"username",
"password",
options,
{ result ->
if (result.isSignedIn) {
Log.i("AuthQuickstart", "Sign in succeeded")
} else {
Log.i("AuthQuickstart", "Sign in not complete")
}
},
{ Log.e("AuthQuickstart", "Failed to sign in", it) }
)
val options = AWSCognitoAuthSignInOptions.builder()
.authFlowType(AuthFlowType.CUSTOM_AUTH_WITH_SRP)
.build()
try {
val result = Amplify.Auth.signIn("username", "password", options)
if (result.isSignedIn) {
Log.i("AuthQuickstart", "Sign in succeeded")
} else {
Log.e("AuthQuickstart", "Sign in not complete")
}
} catch (error: AuthException) {
Log.e("AuthQuickstart", "Sign in failed", error)
}
AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
.authFlowType(AuthFlowType.CUSTOM_AUTH_WITH_SRP)
.build();
RxAmplify.Auth.signIn("username", "password", options)
.subscribe(
result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
error -> Log.e("AuthQuickstart", error.toString())
);