Amazon Cognito MFA Implementation Guide
Implement multi-factor authentication with Cognito using TOTP, SMS, and adaptive authentication for enhanced security.
Multi-factor authentication (MFA) is essential for protecting user accounts. Amazon Cognito provides flexible MFA options including TOTP, SMS, and adaptive authentication.
Configuring User Pool MFA
Enable MFA Settings
CognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: SecureUserPool
MfaConfiguration: OPTIONAL # or REQUIRED
EnabledMfas:
- SOFTWARE_TOKEN_MFA
- SMS_MFA
SmsConfiguration:
SnsCallerArn: !GetAtt CognitoSNSRole.Arn
ExternalId: cognito-sms-external-id
SoftwareTokenMfaConfiguration:
Enabled: true
AccountRecoverySetting:
RecoveryMechanisms:
- Name: verified_email
Priority: 1
- Name: verified_phone_number
Priority: 2
User Pool Client Configuration
UserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: WebAppClient
UserPoolId: !Ref CognitoUserPool
ExplicitAuthFlows:
- ALLOW_USER_SRP_AUTH
- ALLOW_REFRESH_TOKEN_AUTH
PreventUserExistenceErrors: ENABLED
EnableTokenRevocation: true
AuthSessionValidity: 3
TOTP MFA Implementation
Associate TOTP
import boto3
cognito = boto3.client('cognito-idp')
def setup_totp_mfa(access_token):
# Get secret code for authenticator app
response = cognito.associate_software_token(
AccessToken=access_token
)
secret_code = response['SecretCode']
session = response.get('Session')
# Generate QR code URI for authenticator apps
qr_uri = f"otpauth://totp/MyApp:user@example.com?secret={secret_code}&issuer=MyApp"
return {
'secret_code': secret_code,
'qr_uri': qr_uri,
'session': session
}
def verify_totp_setup(access_token, user_code, friendly_name='Authenticator'):
response = cognito.verify_software_token(
AccessToken=access_token,
UserCode=user_code,
FriendlyDeviceName=friendly_name
)
if response['Status'] == 'SUCCESS':
# Set MFA preference
cognito.set_user_mfa_preference(
AccessToken=access_token,
SoftwareTokenMfaSettings={
'Enabled': True,
'PreferredMfa': True
}
)
return True
return False
TOTP Authentication Flow
def authenticate_with_mfa(username, password, user_pool_id, client_id):
# Initial authentication
response = cognito.initiate_auth(
ClientId=client_id,
AuthFlow='USER_SRP_AUTH',
AuthParameters={
'USERNAME': username,
'SRP_A': calculate_srp_a()
}
)
# Handle MFA challenge
if response.get('ChallengeName') == 'SOFTWARE_TOKEN_MFA':
mfa_code = get_user_mfa_code() # Get from user
response = cognito.respond_to_auth_challenge(
ClientId=client_id,
ChallengeName='SOFTWARE_TOKEN_MFA',
Session=response['Session'],
ChallengeResponses={
'USERNAME': username,
'SOFTWARE_TOKEN_MFA_CODE': mfa_code
}
)
return response.get('AuthenticationResult')
Adaptive Authentication
Advanced Security Features
UserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolAddOns:
AdvancedSecurityMode: ENFORCED
LambdaConfig:
PreAuthentication: !GetAtt PreAuthLambda.Arn
PostAuthentication: !GetAtt PostAuthLambda.Arn
DefineAuthChallenge: !GetAtt DefineChallengeLambda.Arn
CreateAuthChallenge: !GetAtt CreateChallengeLambda.Arn
VerifyAuthChallengeResponse: !GetAtt VerifyChallengeLambda.Arn
Risk-Based Authentication Lambda
def pre_authentication_handler(event, context):
user_context = event.get('request', {}).get('userContextData')
risk_level = assess_risk(
ip_address=user_context.get('ipAddress'),
device_fingerprint=user_context.get('encodedData'),
user_agent=event.get('request', {}).get('validationData', {}).get('User-Agent')
)
if risk_level == 'HIGH':
event['response']['autoConfirmUser'] = False
event['response']['autoVerifyPhone'] = False
# Force MFA for high-risk authentications
return event
def assess_risk(ip_address, device_fingerprint, user_agent):
risk_score = 0
# Check IP reputation
if is_tor_exit_node(ip_address) or is_vpn(ip_address):
risk_score += 30
# Check device
if not is_known_device(device_fingerprint):
risk_score += 20
# Check location
if is_unusual_location(ip_address):
risk_score += 25
# Check time
if is_unusual_time():
risk_score += 15
if risk_score >= 50:
return 'HIGH'
elif risk_score >= 25:
return 'MEDIUM'
return 'LOW'
Device Tracking
def remember_device(access_token, device_key, device_name):
cognito.confirm_device(
AccessToken=access_token,
DeviceKey=device_key,
DeviceSecretVerifierConfig={
'PasswordVerifier': calculate_device_verifier(),
'Salt': generate_salt()
},
DeviceName=device_name
)
# Update device status
cognito.update_device_status(
AccessToken=access_token,
DeviceKey=device_key,
DeviceRememberedStatus='remembered'
)
Working with Warqline
We are a cloud engineering consultancy and an official AWS and Google Cloud partner. If you are running this in production and want a second pair of eyes, we scope work in a free 45-minute technical call: you describe what you are running and what worries you, and we tell you what we would look at first.
Conclusion
Cognito MFA provides flexible, secure authentication options. Combine TOTP, adaptive authentication, and device tracking for comprehensive user protection.