Couple of weeks ago I was involved in a hackathon which involved integrating two Cognito user pools together. During my investigation I discovered that Cognito user pool supports OAuth2 for user authentication. This post will outline how you can use Cognito user pool as an OIDC provider as well as how you can connect two user pools together.
Who is this post for?
This post is for you if you:
- Have basic understanding of AWS Cognito user pools
- Want to know how Cognito user pools can be used as a OIDC provider
- How to associate two user pools together through federated identity providers
Sections
What is OpenID Connect?
OpenID is a protocol which provides a mechanism to authenticate users through a third party. This means that users can login to your application with existing accounts on other platforms. When a user completes the OIDC flow, your application can gain access to some of their information from the third party in the form of an id_token
which is a JWT token.
User Pool Setup
In this section we'll create two Cognito user pools and configure them so they can integrate together. oidc-pool-1
will be the master user pool which uses oidc-pool-2
as a federated identity provider. We'll create a user in oidc-pool-2
and keep oidc-pool-1
empty.
Search for Cognito on the AWS console and click on Manage User Pools. Click Create a user pool on the top right corner.
After entering the name of your user pool, you are presented with two options. I'll be clicking Review defaults for the purpose of this demo but you're welcome to step through the settings. This option will let you specify some crucial settings for your user pool such as required attributes for a user. Note that this information cannot be changed once you create your user pool.
Once you've created a user pool, navigate to App clients.
An app client has access to invoke certain endpoints on your user pool while being unauthenticated. Decide on a name and create the app client. We'll leave rest of the settings as is.
Head over to the Domain name page and register a domain for your user pool. Take note of the domain that you enter here.
Repeat the process above and create another user pool. Apply the exact same configuration as the first user pool. Take note of the App client id and App client secret as well as the Pool Id for the second user pool, we will need this when we integrate the two user pools together.
If you followed the post up to this point, you'll now have two Cognito user pools, each with an app client and a domain. If you're satisfied with your setup, navigate to App client settings of your second user pool.
This is where the integration begins. Choose Select all for Enabled Identity Providers and set the Callback URL(s) in the following format:
https://${USER_POOL_DOMAIN}/oauth2/idpresponse
This allows users authenticated with the second user pool to be redirected to the master user pool.
Since I didn't prepare any web app to demo this integration, I'm setting a random value on the Sign out URL(s).
Select Authorization code grant and openid under OAuth 2.0 and click Save changes.
Configuring Federated Identity Provider
Cognito user pools support integration with federated identity providers such as Google and Facebook. We'll use this feature to integrate our user pools together.
Navigate to Identity providers on the first user pool. Select OpenID Connect and you'll see the form below.
Here's how you should fill in the form:
Provider name: Arbitrary name
Client ID: App client id of the second user pool
Client secret: App client secret of the second user pool
Attributes request method: GET
Authorize scope: openid
Issuer: https://cognito-idp.${REGION}.amazonaws.com/${SECOND_USER_POOL_ID}
User pool ID can be found on the General settings menu. Click on Run discovery once you've filled in the form.
Don't be worried if you see this warning.
Open a new tab in your browser and navigate to https://cognito-idp.${REGION}.amazonaws.com/${SECOND_USER_POOL_ID}/.well-known/openid-configuration. You'll see a JSON response with a set of properties. This information can be used to fill in the rest of the form.
Authorization endpoint: https://${SECOND_USER_POOL_DOMAIN}/oauth2/authorize
Token endpoint: https://${SECOND_USER_POOL_DOMAIN}/oauth2/token
Userinfo endpoint: https://${SECOND_USER_POOL_DOMAIN}/oauth2/userInfo
Jwks uri: https://cognito-idp.${REGION}.amazonaws.com/${SECOND_USER_POOL_ID}/.well-known/jwks.json
Click on Create provider Once you've filled in the form completely.
Navigate to App client settings on your master user pool. Select the name of the federated identity provider that you just added (and Cognito User Pool if you want to support direct login through this client). Add suitable URLs for callback and sign out. Check Authorization code grant and openid in OAuth 2.0 and click on Save changes. There is only one step left to integrate the two user pools.
Navigate to Attribute mapping page of the master user pool. Click on the OIDC tab. This form indicates how the attributes of the second user pool maps to the attributes of the master user pool.
When you land on this page for the first time, you'll only see a sub
attribute. This is a built-in mapping which acts as a unique identifier of the user. If you're using the default user pool configurations you can add the email related mappings as can be seen above. Otherwise you'll want to map whatever attribute makes sense for your use case. Note that you must add attributes that are marked as required on your master user pool. Click on Save changes once you're happy with the attribute mapping.
This marks the end of this integration! Continue to the next section if you want to find out how you can test it using Cognito Hosted UI.
Testing
To simply the testing process, we'll be using Cognito Hosted UI. This is a built-in set of UI elements that allows users to perform basic auth flows such as sign-in, sign-up and sign-out. In reality, you might be using a custom web app with a library such as AWS Amplify to simplify the authentication process.
Navigate to Users and groups on the second user pool and create a user. For the sake of this post I'll have Mark email as verified ticked. If you're using the same user pool configuration as I am, your user will be in FORCE_CHANGE_PASSWORD state.
Navigate to App client settings on your master user pool and click on Launch Hosted UI.
If you selected both YOUR_OIDC_PROVIDER_NAME and Cognito User Pool on your *App client settings, you'll see the same page as I do. Click on the button below Sign in with your corporate ID.
From this page you can sign in as the user you've created on your second user pool.
Depending on your user pool configurations, you might see this page when you sign in. Simply enter a new password for your user. After this step you may notice that your user in the second user pool is now in a CONFIRMED state. Try logging in again on the Hosted UI.
If you're redirected to google.com (or whatever your redirect URL on the master user pool is) with the code
in the query parameter, you've set everything up correctly and the integration is working as expected! Head over to Users and groups on your master user pool to confirm that a new user has been created (it was previously empty). This user should have correct attributes pulled from the second user pool.
Conclusion
We've seen how Cognito user pool can be used as an OIDC provider as well as how we can use this concept to associate two user pools together. If you want to integrate your user pool with another service, you can use the same endpoints provided on this post.
Lastly if you want to integrate this flow with a web app, I again recommend looking into AWS Amplify and how it handles authentication.
Top comments (5)
We’ve currently built our own login screens using amplify, but with the flow demonstrated in this post, it only allows redirecting to the aws hosted UI interface. How can we set it up so that it redirects to our custom built front end url? Thanks!
I wrote up an updated tutorial just since the UI and options have changed significantly since this post:
dev.to/aws-builders/cognito-incept...
Great guide, but if you are getting here to the comments section, I might not recommend using cognito. There are too many problems concerning problems there: dev.to/authress/aws-cognito-dont-g...
How to implement the Logout of the OIDC Provider?
great article! I am pretty sure I set this up to the "T" as prescribed here but when choosing this IDP from Cognito UI I get "Login option is not available. Please try another one"