I've implemented a custom authentication flow in AWS Cognito. I've configured the following triggers within the AWS Cognito User Pool:
- Define Auth Challenge
- Create Auth Challenge
- Verify Auth Challenge Response
On the front end, I'm utilizing Vue.js for the Sign-In process, employing the following code:
import { CognitoUser, CognitoUserPool, AuthenticationDetails } from "amazon-cognito-identity-js"
doSignIn({ email, password }) {
return new Promise((resolve) => {
email = email.toLowerCase().trim()
const authenticationData = {
Username: email,
Password: password,
}
const authenticationDetails = new AuthenticationDetails(authenticationData)
const userPool = new CognitoUserPool(poolDetails)
const userData = {
Username: email,
Pool: userPool,
}
const cognitoUser = new CognitoUser(userData)
const onSuccess = () => {
resolve(true)
}
const onFailure = (err) => {
console.log("onFailure:", err)
resolve(err)
}
const newPasswordRequired = () => {
//
}
const customChallenge = (challengeParameters) => {
const otp = window.prompt(challengeParameters.prompt)
cognitoUser.sendCustomChallengeAnswer(otp, {
onSuccess,
onFailure,
})
}
cognitoUser.setAuthenticationFlowType("CUSTOM_AUTH")
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess,
onFailure,
newPasswordRequired,
customChallenge,
})
})
}
My concern arises from the fact if I do not explicitly set 'cognitoUser.setAuthenticationFlowType("CUSTOM_AUTH")' in the front end, users can still sign in successfully, but without triggering the createAuthChallenge that creates the OTP challenge. Users obtain a valid token that passes through the API gateway without any issue, which is not what I expected. I want to ensure that the user has completed the challenge before obtaining a token.
I'm looking for a solution to either enforce the use of 'cognitoUser.setAuthenticationFlowType("CUSTOM_AUTH")' without relying on client-side configuration or to determine at the API gateway when a token was created following successful challenge completion.
I thought the easiest way would be for the event object in the Lambda function would contain a property that would indicate whether the token was created following a successful challenge. However, I have not found a way to achieve this.
The other way I considered involves utilizing a shared property in the response within 'verifyAuthChallengeResponse', which could then be accessed during 'preTokenGeneration'. If the preTokenGeneration was triggered without going through the 'verifyAuthChallengeResponse', I would throw an error. However, I'm not sure if that's possible or even the best approach.
exports.verifyAuthChallengeResponse = async event => {
console.log("verifyAuthChallengeResponse ~ JSON.event:", JSON.stringify(event))
event.response.answerCorrect = event.request.privateChallengeParameters.answer === event.request.challengeAnswer
//For intance, I could use a shared property here
event.response.DATA_SHARED = event.response.answerCorrect
return event
}
exports.preTokenGeneration = async event => {
console.log("preTokenGeneration ~ JSON.event:", JSON.stringify(event))
if (!event.response.DATA_SHARED)
throw new Error("The user did not pass the custom challenge")
return event
}
Any help would be appreciated.