If you want to set up TOTP software token MFA in your user pool, your user needs to signs in with a user name and password, then uses a TOTP to complete authentication.

After your user sets and verifies a user name and password, they can activate a TOTP software token for MFA.

You can activate TOTP MFA for your user pool in the Amazon Cognito console, or you can use Amazon Cognito API operations. At the user pool level, you can call SetUserPoolMfaConfig to configure MFA and enable TOTP MFA.

Table of Content :

Configuring TOTP for your user is a multi-step process where your user receives a secret code that they validate by entering a one-time password. Next, you can enable TOTP MFA for your user or set TOTP as the preferred MFA method for your user.

Amazon cognito set TOTP Software Token MFA

Maven dependencies

<dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-core</artifactId> <version>1.11.764</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-cognitoidp</artifactId> <version>1.11.764</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> <version>1.11.360</version> </dependency>

Create CognitoClient Instance

public static AWSCognitoIdentityProvider getAWSCognitoIdentityClient() { System.setProperty("aws.accessKeyId", "-- your accessKey Id--"); System.setProperty("aws.secretKey", "-- your secret Key--"); AWSCognitoIdentityProvider cognitoClient = AWSCognitoIdentityProviderClientBuilder.standard().withRegion(Regions.AP_SOUTH_1).withCredentials(new SystemPropertiesCredentialsProvider()).build(); return client; }

If TOTP software token MFA isn't enabled for the user pool, users can't associate or verify with the token. They receive a SoftwareTokenMFANotFoundException exception, as follows: "Software Token MFA has not been enabled by the user pool."

Enable software token MFA for pool

You can enable TOTP MFA for your user pool in the Amazon Cognito console, through the Amazon Cognito hosted UI, or using Amazon Cognito APIs. At the user pool level, you can configure MFA and enable TOTP MFA by calling SetUserPoolMfaConfig.

Associate the TOTP Token | AWS Cognito - Enable MFA per user

When your user chooses TOTP software token MFA, call AssociateSoftwareToken to return a unique generated shared secret key code for the user account. The request for this API method takes an access token or a session string, but not both. As a convenience, you can distribute the secret key as a quick response (QR) code.

public InitiateAuthResult loginUser(final String username, final String password) { final AWSCognitoIdentityProvider provider = getAWSCognitoIdentityClient(); final Map<String String> authParams = new HashMap<String >(); authParams.put("USERNAME", username); authParams.put("PASSWORD", password); final InitiateAuthRequest initiateAuthRequest = new InitiateAuthRequest().withClientId(clientId) .withAuthFlow(AuthFlowType.USER_PASSWORD_AUTH).withAuthParameters(authParams); final InitiateAuthResult result = provider.initiateAuth(initiateAuthRequest); log.info("Result Challenge is : " + result.getChallengeName()); return result; } final InitiateAuthResult result = loginUser(username, password); public static String getSecretForAppMFA(final InitiateAuthResult result) { final AWSCognitoIdentityProvider provider = getAWSCognitoIdentityClient(); final AssociateSoftwareTokenRequest associateSoftwareTokenRequest = new AssociateSoftwareTokenRequest(); associateSoftwareTokenRequest.setAccessToken(result.getAuthenticationResult().getAccessToken()); associateSoftwareTokenRequest.setSession(result.getSession()); final AssociateSoftwareTokenResult associateSoftwareTokenResult = provider .associateSoftwareToken(associateSoftwareTokenRequest); associateSoftwareTokenResult.getSecretCode(); log.info("this is a secret code we need to put in google Authenticator app : steps given below"); log.info(associateSoftwareTokenResult.getSecretCode()); log.info("getSecretForAppMFA : secret code generated successfully.This code you have to put in Sodtware MFA app like google Auth."); return associateSoftwareTokenResult.getSecretCode(); }

Set google auth using the secret key

In google Auth, we have to enter generated secret code as,

 Account Name - your user name
Your key - Secrete returned by above
Type of Key - Time-Based

Verify the TOTP Token

After a new TOTP account is associated with your app, it generates a temporary password(6 digit code).

Your user enters the temporary password into your app, which responded with a call to VerifySoftwareToken. On the Amazon Cognito service server, a TOTP code is generated and compared with your user's temporary password. If they match, then the service marks it as verified.

If the code is correct, check that the time used is in the range and within the maximum number of retries. Amazon Cognito also accepts TOTP tokens that are one 30 second window early or late to account for clock skew. If your user passes all of the steps, the verification is complete.

Or, if the code is wrong, the verification cannot be finished and your user can either try again or cancel. We recommend that your user sync the time of their TOTP-generating app.

In our case we are using AWS Java SDK, so we need to call loginUser(username, password, code from google)

public static VerifySoftwareTokenResult verifySoftwareTokenForAppMFA(final AWSCognitoIdentityProvider provider, final InitiateAuthResult result, final String code) throws Exception { try { final VerifySoftwareTokenRequest verifySoftwareTokenRequest = new VerifySoftwareTokenRequest(); if (result.getAuthenticationResult() != null) { verifySoftwareTokenRequest.setAccessToken(result.getAuthenticationResult().getAccessToken()); } if (result.getSession() != null) { verifySoftwareTokenRequest.setSession(result.getSession()); } verifySoftwareTokenRequest.setUserCode(code);// 6 digit code from google Auth final VerifySoftwareTokenResult verifySoftwareTokenResult = provider .verifySoftwareToken(verifySoftwareTokenRequest); log.info("Software token verified"); log.info(verifySoftwareTokenResult.getSession()); return verifySoftwareTokenResult; } catch (final Exception ex) { log.error(ex.getMessage()); } } }

Set user MFA prefernces

After verifying verifySoftwareTokenResult we need to set user MFA preferences as given below.

public static void registerSoftwareMFAPreferences(final String username, final String userPoolId) { final AWSCognitoIdentityProvider provider = getAWSCognitoIdentityClient(); final SoftwareTokenMfaSettingsType softwareTokenMfaSettings1 = new SoftwareTokenMfaSettingsType() .withPreferredMfa(true).withEnabled(true); final AdminSetUserMFAPreferenceRequest adminSetUserMFAPreferenceRequest = new AdminSetUserMFAPreferenceRequest() .withSoftwareTokenMfaSettings(softwareTokenMfaSettings1).withUsername(username) .withUserPoolId(userPoolId); provider.adminSetUserMFAPreference(adminSetUserMFAPreferenceRequest); log.info("SoftwareMFAPreferences set suucessfully"); }

Sign in with TOTP MFA

Your user enters their user name and password to sign in to your client app.

The TOTP MFA challenge is invoked and your user is prompted by your app to enter a temporary password.

Your user gets the temporary password from an associated TOTP-generating app.

Your user enters the TOTP code into your client app. Your app notifies the Amazon Cognito service to verify it. For each sign-in, RespondToAuthChallenge should be called to get a response to the new TOTP authentication challenge.

If the token is verified by Amazon Cognito, the sign-in is successful and your user continues with the authentication flow.

When we verified Verify TOTP Token and set the MFA preferences, we set go.our software MFA is set for given user.

We can log in using username, password, and MFA code from google authenticator.

here is the final code for login.

final AWSCognitoIdentityProvider provider = getAWSCognitoIdentityClient(); final InitiateAuthResult result = loginUser(username, password); if (result.getChallengeName() != null && result.getChallengeName().equals("SOFTWARE_TOKEN_MFA")) { log.info("SOFTWARE_TOKEN_MFA challenge is generated"); final Map<String String> challengeResponses = new HashMap<String String>(); challengeResponses.put("USERNAME", username); challengeResponses.put("SOFTWARE_TOKEN_MFA_CODE", mfaCode); final RespondToAuthChallengeRequest respondToAuthChallengeRequest = new RespondToAuthChallengeRequest() .withChallengeName(ChallengeNameType.SOFTWARE_TOKEN_MFA).withClientId(clientId) .withChallengeResponses(challengeResponses).withSession(result.getSession()); final RespondToAuthChallengeResult respondToAuthChallengeResult = provider .respondToAuthChallenge(respondToAuthChallengeRequest); log.info("MFA Login Successfully for APP MFA and the result is {} : ", respondToAuthChallengeResult.getChallengeName()); log.info("respondToAuthChallengeResult.getAuthenticationResult()" + respondToAuthChallengeResult.getAuthenticationResult()); }

In this article, we have seen AWS Cognito TOTP Software Token MFA Using Java. All source code in the article can be found in the GitHub repository.