I am working with Cognito Passwordless in AWS for my Ruby on Rails API project. I have created the 3 needed lambdas(DefineAuthChallenge, CreateAuthChallenge and VerifyAuthChallengeResponse) and it works fine but I want to allow the user to have multiple attempts to enter the correct verification code needed to login.
My problem is that if the user fails the first attempt in the second one, after entering the correct verification code, I always get the same message from Cognito(“Invalid session for the user”).
Digging a little bit more in the problem and checking the logs I realized that the lambda VerifyAuthChallengeResponse is only executed the first time and in the DefineAuthChallenge the second attempt is not beeing registered.
Any help?
My lambdas are something like this.
DefineAuthChallenge
def lambda_handler(event:, context:)
puts "Event: #{event.inspect}"
if event['triggerSource'] == 'DefineAuthChallenge_Authentication'
session = event.dig('request', 'session') || []
puts "Session: #{session.inspect}"
if session.empty?
# New request to log in
puts "New request to log in"
event['response'] = {
'challengeName' => 'CUSTOM_CHALLENGE',
'issueTokens' => false,
'failAuthentication' => false
}
elsif session.length >= 2 && !session.last['challengeResult']
# User has incorrectly entered OTP 2 times
puts "User has incorrectly entered OTP 2 times"
event['response'] = {
'issueTokens' => false,
'failAuthentication' => true
}
elsif session.any? { |attempt| attempt['challengeName'] == 'CUSTOM_CHALLENGE' && attempt['challengeResult'] }
# User correctly entered OTP
puts "User correctly entered OTP"
event['response'] = {
'issueTokens' => true,
'failAuthentication' => false
}
else
# User incorrectly entered OTP - resend code
puts "User incorrectly entered OTP - resend code"
event['response'] = {
'challengeName' => 'CUSTOM_CHALLENGE',
'issueTokens' => false,
'failAuthentication' => false
}
end
end
puts "Response: #{event['response'].inspect}"
event
end
CreateAuthChallenge
require 'aws-sdk-ses'
def lambda_handler(event:, context:)
puts "Event: #{event.inspect}"
if event['triggerSource'] == 'CreateAuthChallenge_Authentication'
code = generate_code
send_verification_code(event['request']['userAttributes']['email'], code)
event['response'] = {
'publicChallengeParameters' => { 'email' => event['request']['userAttributes']['email'] },
'privateChallengeParameters' => { 'secretLoginCode' => code },
'challengeMetadata' => 'CODE_DELIVERY'
}
end
puts "Response: #{event['response'].inspect}"
event
end
def generate_code
rand(100000..999999).to_s
end
def send_verification_code(email, code)
ses = Aws::SES::Client.new(region: '*******')
user_status_message = "Welcome!"
ses.send_email({
destination: { to_addresses: [email] },
message: {
body: {
text: {
charset: 'UTF-8',
data: "#{user_status_message}nYour verification code is #{code}"
}
},
subject: {
charset: 'UTF-8',
data: 'Your verification code'
}
},
source: '***@***.***'
})
end
VerifyAuthChallengeResponse
def lambda_handler(event:, context:)
puts "Event: #{event.inspect}"
if event['triggerSource'] == 'VerifyAuthChallengeResponse_Authentication'
expected_answer = event['request']['privateChallengeParameters']['secretLoginCode']
provided_answer = event['request']['challengeAnswer']
puts "Expected Answer: #{expected_answer}"
puts "Provided Answer: #{provided_answer}"
if provided_answer == expected_answer
event['response']['answerCorrect'] = true
puts "Answer is correct"
else
event['response']['answerCorrect'] = false
puts "Answer is incorrect"
end
end
puts "Response: #{event['response'].inspect}"
event
end