Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save maskaravivek/b2fb462f93c5c2789d4e7c652972976d to your computer and use it in GitHub Desktop.
Save maskaravivek/b2fb462f93c5c2789d4e7c652972976d to your computer and use it in GitHub Desktop.
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