Skip to content

Instantly share code, notes, and snippets.

@JLarky
Created February 12, 2021 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JLarky/caf6ecdacf5826fd878c655e04c394c3 to your computer and use it in GitHub Desktop.
Save JLarky/caf6ecdacf5826fd878c655e04c394c3 to your computer and use it in GitHub Desktop.
Pulumi: create AWS cognito user pool to use with AWS amplify including some lambda triggers with permissions and stuff for `lambdaConfig` to work
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
import * as cloud from "@pulumi/cloud";
import type { CognitoUserPoolTriggerEvent } from "aws-lambda";
const config = new pulumi.Config();
const project = "my";
const stack = pulumi.getStack();
// identity pool is needed to keep track of anonymous accounts (no email/password)
// const identityPool = new aws.cognito.IdentityPool(`${project}-${stack}-identity-pool`, {
// identityPoolName: `${project} ${stack} identity pool`,
// });
const customMessageLambda = new aws.lambda.CallbackFunction(
`${project}-${stack}-customMessage-lambda`,
{
// policies: [iam.AWSLambdaFullAccess], by default
callback: async (event: CognitoUserPoolTriggerEvent) => {
console.log(event);
//
if (event.userPoolId === "theSpecialUserPool" || true) {
// Identify why was this function invoked
if (event.triggerSource === "CustomMessage_SignUp") {
// Ensure that your message contains event.request.codeParameter. This is the placeholder for code that will be sent
event.response.smsMessage =
"Welcome to my project. Your confirmation code is " + event.request.codeParameter;
// event.response.emailSubject = "Please verify your email addresss";
// // TODO: html template https://www.mihaiblaga.dev/aws-cognito-custom-email-verification-template
// // TODO: add `preheader` https://sendgrid.com/blog/perfecting-your-email-preview-text/ see email with twitch code
// event.response.emailMessage = `<!DOCTYPE html><html></html>`;
event.response.emailSubject = "Welcome to my project";
event.response.emailMessage =
"Thank you for signing up. " +
event.request.codeParameter +
" is your verification code";
}
// Create custom message for other events
}
// Customize messages for other user pools
// Return to Amazon Cognito
return event;
},
}
);
const preSignUpLambda = new aws.lambda.CallbackFunction(`${project}-${stack}-preSignUp-lambda`, {
// policies: [iam.AWSLambdaFullAccess], by default
callback: async (event: CognitoUserPoolTriggerEvent, context) => {
// SEE https://franzwong.medium.com/howto-integrate-google-recaptcha-with-aws-cognito-e47466e908bb and https://stackoverflow.com/questions/45545267/aws-cognito-bot-prevention-with-google-recaptcha
console.log(event);
try {
if (!event.request.validationData) {
throw new Error("Missing validation data");
}
const recaptchaToken: string = event.request.validationData.recaptchaToken;
if (recaptchaToken !== "example token") {
throw new Error("wrong recaptchaToken");
}
return event;
} catch (e) {
console.error(e);
const myErrorObj = {
errorType: "InternalServerError",
httpStatus: 500,
requestId: context.awsRequestId,
message: "An unknown error has occurred. Please try again.",
};
throw new Error(JSON.stringify(myErrorObj));
}
},
});
// user pool is needed to store users (email/password)
const userPool = new aws.cognito.UserPool(`${project}-${stack}-user-pool`, {
// see https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html
// and https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases
// and https://github.com/aws-samples/amazon-cognito-passwordless-email-auth/blob/caf2de4d286f626230d91670dbf5b09d232f340d/cognito/template.yaml#L112
// and https://docs.aws.amazon.com/cognito/latest/developerguide/signing-up-users-in-your-app.html
schemas: [
{
name: "name",
attributeDataType: "String",
mutable: true,
required: true,
stringAttributeConstraints: { minLength: "0", maxLength: "2048" },
},
{
name: "email",
attributeDataType: "String",
mutable: true,
required: true,
stringAttributeConstraints: { minLength: "0", maxLength: "2048" },
},
],
usernameConfiguration: { caseSensitive: false },
//
usernameAttributes: ["email"], // sign in with email and uses UUID as immutable username // required by https://aws.amazon.com/blogs/mobile/implementing-passwordless-email-authentication-with-amazon-cognito/
// aliasAttributes: ["email"], // alternatively sign in with immutable username OR (mutable) email
mfaConfiguration: "OFF",
// mfaConfiguration: "ON",
// smsAuthenticationMessage: "Your code is {####}",
// smsConfiguration: {
// externalId: "example",
// snsCallerArn: aws_iam_role.example.arn,
// },
// softwareTokenMfaConfiguration: {
// enabled: true,
// },
passwordPolicy: {
minimumLength: 10,
requireLowercase: true,
requireUppercase: false,
requireNumbers: true,
requireSymbols: false,
temporaryPasswordValidityDays: 7,
},
lambdaConfig: pulumi.all([customMessageLambda.arn, preSignUpLambda.arn]).apply(
// https://github.com/pulumi/pulumi-aws/issues/678
([customMessageArn, preSignUpArn]): aws.types.input.cognito.UserPoolLambdaConfig => ({
customMessage: customMessageArn,
preSignUp: preSignUpArn,
})
),
// lambdaConfig: {
// createAuthChallenge: "",
// defineAuthChallenge: "",
// preSignUp: "",
// verifyAuthChallengeResponse: "",
// postAuthentication: "",
// },
// accountRecoverySetting: {
// recoveryMechanisms: [
// {
// name: "verified_email",
// priority: 1,
// },
// {
// name: "verified_phone_number",
// priority: 2,
// },
// ],
// },
autoVerifiedAttributes: ["email"], // `Which attributes do you want to verify?` in UI
deviceConfiguration: { challengeRequiredOnNewDevice: true },
});
// this is to test magic link login later
const passwordlessAuthClient = new aws.cognito.UserPoolClient(
`${project}-${stack}-user-pool-passwordless-client`,
{
generateSecret: false,
userPoolId: userPool.id,
explicitAuthFlows: ["CUSTOM_AUTH_FLOW_ONLY"], // required by https://aws.amazon.com/blogs/mobile/implementing-passwordless-email-authentication-with-amazon-cognito/
}
);
// this is to test login
const defaultAuthClient = new aws.cognito.UserPoolClient(
`${project}-${stack}-user-pool-default-client`,
{
// https://youtu.be/KK8FfF3yaok?t=883
generateSecret: false,
userPoolId: userPool.id,
callbackUrls: ["http://localhost:3100/login/?cognito=1"],
logoutUrls: ["http://localhost:3100/logout/?cognito=1"],
allowedOauthFlowsUserPoolClient: true,
allowedOauthFlows: ["code"],
allowedOauthScopes: ["email", "openid", "profile"],
supportedIdentityProviders: ["COGNITO"], // got it from chrome dev tools, thanks AWS
}
);
// FIXME: WAIT FOR https://github.com/hashicorp/terraform-provider-aws/issues/16479 to be fixed first
// const userPoolDomain = new aws.cognito.UserPoolDomain(`${project}-${stack}-user-pool-domain`, {
// domain: `${project}-${stack}-dpc3`,
// userPoolId: userPool.id,
// });
const allowCognito = new aws.lambda.Permission(`${project}-${stack}-allow-custom-message`, {
action: "lambda:InvokeFunction",
"function": customMessageLambda.name,
principal: "cognito-idp.amazonaws.com",
sourceArn: userPool.arn,
// qualifier: testAlias.name, // I don't know if we need that
});
const allowPreSignup = new aws.lambda.Permission(`${project}-${stack}-allow-pre-signup`, {
action: "lambda:InvokeFunction",
"function": preSignUpLambda.name,
principal: "cognito-idp.amazonaws.com",
sourceArn: userPool.arn,
});
export const cognitoClientId = defaultAuthClient.id;
// export const userPoolDomainName = userPoolDomain.domain;
// for login with google through cognito
// const exampleProvider = new aws.cognito.IdentityProvider("exampleProvider", {
// userPoolId: userPool.id,
// providerName: "Google",
// providerType: "Google",
// providerDetails: {
// authorize_scopes: "email",
// client_id: "your client_id",
// client_secret: "your client_secret",
// },
// attributeMapping: {
// email: "email",
// username: "sub",
// },
// });
{
"name": "pulimi-cognito-stuff",
"version": "0.1.0",
"devDependencies": {
"@types/node": "^13.13.2",
"@pulumi/aws": "^3.23.0",
"@pulumi/awsx": "^0.20.0",
"@pulumi/cloud": "^0.20.0",
"@pulumi/cloud-aws": "^0.20.0",
"@pulumi/pulumi": "^2.0.0",
"@types/mime": "^2.0.1"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment