Created
May 28, 2023 21:34
-
-
Save maskaravivek/b2fb462f93c5c2789d4e7c652972976d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const AWS = require("aws-sdk"); | |
| exports.handler = async (event) => { | |
| try { | |
| const { | |
| triggerSource, | |
| userPoolId, | |
| userName, | |
| request: { | |
| // You won't have given_name and family_name attributes | |
| // if you haven't specified them as required when the user registers | |
| userAttributes: { email, given_name, family_name }, | |
| }, | |
| } = event; | |
| const EXTERNAL_AUTHENTICATION_PROVIDER = 'PreSignUp_ExternalProvider'; | |
| if (triggerSource === EXTERNAL_AUTHENTICATION_PROVIDER) { | |
| // --> User has registered with Google/Facebook external providers | |
| const usersFilteredByEmail = await listUsersByEmail({ | |
| userPoolId, | |
| email, | |
| }); | |
| // userName example: "Facebook_12324325436" or "Google_1237823478" | |
| const [providerNameValue, providerUserId] = userName.split('_'); | |
| // Uppercase the first letter because the event sometimes | |
| // has it as google_1234 or facebook_1234. In the call to `adminLinkProviderForUser` | |
| // the provider name has to be Google or Facebook (first letter capitalized) | |
| const providerName = | |
| providerNameValue.charAt(0).toUpperCase() + providerNameValue.slice(1); | |
| if (usersFilteredByEmail.Users && usersFilteredByEmail.Users.length > 0) { | |
| // user already has cognito account | |
| const cognitoUsername = | |
| usersFilteredByEmail.Users[0].Username || 'username-not-found'; | |
| // if they have access to the Google / Facebook account of email X, verify their email. | |
| // even if their cognito native account is not verified | |
| await adminLinkUserAccounts({ | |
| username: cognitoUsername, | |
| userPoolId, | |
| providerName, | |
| providerUserId, | |
| }); | |
| } else { | |
| /* --> user does not have a cognito native account -> | |
| 1. create a native cognito account | |
| 2. change the password, to change status from FORCE_CHANGE_PASSWORD to CONFIRMED | |
| 3. merge the social and the native accounts | |
| 4. add the user to a group - OPTIONAL | |
| */ | |
| const createdCognitoUser = await adminCreateUser({ | |
| userPoolId, | |
| email, | |
| // these are attributes that you require upon registration | |
| givenName: given_name, | |
| familyName: family_name, | |
| }); | |
| await adminSetUserPassword({ userPoolId, email }); | |
| const cognitoNativeUsername = | |
| createdCognitoUser.User?.Username || 'username-not-found'; | |
| await adminLinkUserAccounts({ | |
| username: cognitoNativeUsername, | |
| userPoolId, | |
| providerName, | |
| providerUserId, | |
| }); | |
| // OPTIONALLY add the user to a group | |
| await adminAddUserToGroup({ | |
| userPoolId, | |
| username: cognitoNativeUsername, | |
| groupName: 'Users', | |
| }); | |
| event.response.autoVerifyEmail = true; | |
| event.response.autoConfirmUser = true; | |
| } | |
| } | |
| return event; | |
| } catch (err) { | |
| return event; | |
| } | |
| }; | |
| const listUsersByEmail = async ({ | |
| userPoolId, | |
| email, | |
| }) => { | |
| const params = { | |
| UserPoolId: userPoolId, | |
| Filter: `email = "${email}"`, | |
| }; | |
| const cognitoIdp = new AWS.CognitoIdentityServiceProvider(); | |
| return cognitoIdp.listUsers(params).promise(); | |
| }; | |
| const adminLinkUserAccounts = async ({ | |
| username, | |
| userPoolId, | |
| providerName, | |
| providerUserId, | |
| }) => { | |
| const params = { | |
| DestinationUser: { | |
| ProviderAttributeValue: username, | |
| ProviderName: 'Cognito', | |
| }, | |
| SourceUser: { | |
| ProviderAttributeName: 'Cognito_Subject', | |
| ProviderAttributeValue: providerUserId, | |
| ProviderName: providerName, | |
| }, | |
| UserPoolId: userPoolId, | |
| }; | |
| const cognitoIdp = new AWS.CognitoIdentityServiceProvider(); | |
| return new Promise((resolve, reject) => { | |
| cognitoIdp.adminLinkProviderForUser(params, (err, data) => { | |
| if (err) { | |
| reject(err); | |
| return; | |
| } | |
| resolve(data); | |
| }); | |
| }); | |
| }; | |
| const adminCreateUser = async ({ | |
| userPoolId, | |
| email, | |
| givenName, | |
| familyName, | |
| }) => { | |
| const params = { | |
| UserPoolId: userPoolId, | |
| // SUPRESS prevents sending an email with the temporary password | |
| // to the user on account creation | |
| MessageAction: 'SUPPRESS', | |
| Username: email, | |
| UserAttributes: [ | |
| { | |
| Name: 'given_name', | |
| Value: givenName, | |
| }, | |
| { | |
| Name: 'family_name', | |
| Value: familyName, | |
| }, | |
| { | |
| Name: 'email', | |
| Value: email, | |
| }, | |
| { | |
| Name: 'email_verified', | |
| Value: 'true', | |
| }, | |
| ], | |
| }; | |
| const cognitoIdp = new AWS.CognitoIdentityServiceProvider(); | |
| return cognitoIdp.adminCreateUser(params).promise(); | |
| }; | |
| const adminSetUserPassword = async ({ | |
| userPoolId, | |
| email, | |
| }) => { | |
| const params = { | |
| Password: generatePassword(), | |
| UserPoolId: userPoolId, | |
| Username: email, | |
| Permanent: true, | |
| }; | |
| const cognitoIdp = new AWS.CognitoIdentityServiceProvider(); | |
| return cognitoIdp.adminSetUserPassword(params).promise(); | |
| }; | |
| function generatePassword() { | |
| return `${Math.random() // Generate random number, eg: 0.123456 | |
| .toString(36) // Convert to base-36 : "0.4fzyo82mvyr" | |
| .slice(-8)}42`; // Cut off last 8 characters : "yo82mvyr" and add a number because the cognito password policy requires a number | |
| } | |
| function adminAddUserToGroup({ | |
| userPoolId, | |
| username, | |
| groupName, | |
| }) { | |
| const params = { | |
| GroupName: groupName, | |
| UserPoolId: userPoolId, | |
| Username: username, | |
| }; | |
| const cognitoIdp = new AWS.CognitoIdentityServiceProvider(); | |
| return cognitoIdp.adminAddUserToGroup(params).promise(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment