Skip to content

Instantly share code, notes, and snippets.

@mobilequickie
Last active August 4, 2023 03:45
Show Gist options
  • Save mobilequickie/202a7dd1f72a2440b140f9bf44e6e46f to your computer and use it in GitHub Desktop.
Save mobilequickie/202a7dd1f72a2440b140f9bf44e6e46f to your computer and use it in GitHub Desktop.
Amazon Cognito CUSTOM_CHALLENGE Lambda trigger - Create Auth Challenge function
// ### About this Flow ###
// Using Custom Auth Flow through Amazon Cognito User Pools with Lambda Triggers to complete a 'CUSTOM_CHALLENGE'.
//
// ### About this function ###
// This CreateAuthChallengeSMS function (2nd of 4 triggers) creates the type of 'CUSTOM_CHALLENGE' as a one-time pass code sent via SMS. A one-time randomly generated 6-digit code (passCode)
// is sent via SMS (through Amazon SNS) to the user's mobile phone number during authentication. The generated passCode is stored in privateChallengeParameters.passCode and passed to the VerifyAuthChallenge function
// that will verify the user's entered passCode (received via SMS) into the mobile/web app matches the passCode passed privately through privateChallengeParameters.passCode.
// ### Next steps ###
// Instead of using the "crypto-secure-random-digit" library to generate random 6-digit codes, create a base32 secret for the user (if not exist) and
// generate a 6-digit code based on this secret. Much like TOTP except for the secret is never shared with the user. With a base32 secret associated with the user,
// we can easily switch from 6-digit code via SMS to 6-digit code generated based on shared secret via TOTP using the OATH module of a YubiKey or an authenticator app.
//
// Updated: Jan 6, 2020
'use strict';
const crypto_secure_random_digit = require("crypto-secure-random-digit");
const AWS = require("aws-sdk");
var sns = new AWS.SNS();
// Main handler
exports.handler = async (event = {}) => {
console.log('RECEIVED event: ', JSON.stringify(event, null, 2));
let passCode;
var phoneNumber = event.request.userAttributes.phone_number;
// The first CUSTOM_CHALLENGE request for authentication from
// iOS AWSMobileClient actually comes in as an "SRP_A" challenge (a bug in the AWS SDK for iOS?)
// web (Angular) comes in with an empty event.request.session
if (event.request.session && event.request.session.length && event.request.session.slice(-1)[0].challengeName == "SRP_A" || event.request.session.length == 0) {
passCode = crypto_secure_random_digit.randomDigits(6).join('');
await sendSMSviaSNS(phoneNumber, passCode);
} else {
const previousChallenge = event.request.session.slice(-1)[0];
passCode = previousChallenge.challengeMetadata.match(/CODE-(\d*)/)[1];
}
event.response.publicChallengeParameters = { phone: event.request.userAttributes.phone_number };
event.response.privateChallengeParameters = { passCode };
event.response.challengeMetadata = `CODE-${passCode}`;
console.log('RETURNED event: ', JSON.stringify(event, null, 2));
return event;
};
// Send secret code over SMS via Amazon Simple Notification Service (SNS)
async function sendSMSviaSNS(phoneNumber, passCode) {
const params = { "Message": "[MobileQuickie] Your secret code: " + passCode, "PhoneNumber": phoneNumber };
await sns.publish(params).promise();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment