Cognito User Pools is an AWS service that provides applications with user identity and auth. This series of articles cover a full stack solution that enables users to sign in with their Email + Password, Google Sign In, or SSO (SAML), and link all methods to the same user within the app:
This article focuses on using CDK to create our Cognito User Pool resources as Infrastructure as Code (IAC). If you’re already familiar with this you should consider moving onto the next part of this series Sign in with Email, Google, or SAML and link to a single user, since IAC can be a little lengthy (and boring).
Cognito User Pool CDK (IAC)
Let’s start with the basic setup of the Auth construct before we dive into the details defined in the class methods:
User Pool
User Pool Client
We specify up to 2 OAuth callback URLs:
http://localhost:3001/ for local development. Consider removing this for production.
webAppUrl The live web app URL. In Code Genie, this is passed in as either the web app’s custom domain name (if one is defined in cdk.json for the environment we’re deploying) or the default Amplify Hosting URL.
Identity Providers
Define the scopes and attributes from the External IDP that we want to store against our User in our User Pool. We’re grabbing the profilePicture so that we can display the user’s profile picture against their name.
There’s a circular dependency between the Cognito User Pool and the SAML App you create in Google Workspace. Exit early if no GoogleIDPMetadata.xml file exists. When you create the SAML App, you’ll need to provide the UserPoolRedirectUrlACS and UserPoolEntityId values from cdk-outputs.development.json. Download the SAML App’s metadata file and redeploy your CDK Stack.
We must hardcode the SAML Identity Provider name (GOOGLE_SAML_IDENTITY_PROVIDER_NAME) to prevent a second circular dependency between the SAML Identity Provider and the PreSignup Cognito Trigger (which we’ll meet soon). It doesn’t seem like this should be a circular dependency since both resources are attached to the User Pool and the SAML Identity Provider has nothing to do with Triggers, but CDK will give you a “Circular dependency between resources” nonetheless.
Our attribute mappings for the SAML Identity Provider are similar to the Google Identity Provider. Unfortunately we don’t have access to a profile picture, and even though we’re requesting fullname here, Google doesn’t allow you to map it when creating the SAML App. We’ll handle this later.
Triggers
Setting AUTO_VERIFY_USERS in development and testing environments is really convenient. It’s just as convenient in production, but there are good reasons to require email confirmation (such as GDPR compliance).
We add our GOOGLE_SAML_IDENTITY_PROVIDER_NAME environment variable since we’ll need that in the Lambda Function’s code.
Our Lambda Function requires 5 permissions for the User Pool. Unfortunately we can’t specify this.userPool.userPoolArn as the resource since CDK once again complains about a circular dependency. We’re left with granting access to all User Pools within the same account and region.
Environment Config
The cdk.json looks like this:
StringMap
Create External Identity Providers
Google Sign-in
Login to Google Cloud Console and select or create the relevant project.
Select “Web application” as the “Application type” and enter a name
Click “Add URI” under “Authorised JavaScript origins”. Copy the value for UserPoolRedirectUrlACS from cdk-outputs.dev.json and paste in only the domain part (i.e remove the ‘/saml2/idpresponse’).
Click “Add URI” under “Authorised redirect URIs”. Copy the same value from above, but this time add “/oauth2/idpresponse” to the end.
Click “Add app” => “Add custom SAML App”. Enter a name for your app.
Download the metadata file to ./packages/cdk and click Continue.
From cdk-outputs.development.json, copy the values for UserPoolRedirectUrlACS and UserPoolEntityId and paste them into the respective fields in the Service Provider Details form and click Continue.
Add attribute mappings: Primary email => email; First name => first_name; Last name => family_name. Click Finish.
Click the User Access card; select “ON for everyone” and click Save.
Run npm run deploy:dev
End
Now that we’ve created our AWS Cognito User Pool and both External (Sign in with Google) and Internal (SAML) Google Apps, we’re ready to move onto more interesting topics: Sign in with Email, Google, or SAML and link to a single user. This next article focuses on the Lambda Handler logic of the Lambda Functions we created with CDK.