Using SAML IdP Group Mappings with AWS Cognito

Matt Fuller
Apr 15 · 6 min read

AWS Cognito is a popular managed authentication service that provides support for integrated SAML 2.0-compliant identity providers (IdPs) such as Azure Active Directory, Okta, Auth0, OneLogin, and others.

One use case for Cognito is to serve as a middleware or proxy layer between an identity provider and a backend web application. Instead of implementing support for SAML directly into the application (and dealing with the proper security configuration and variety of standards), developers can use Cognito to do the heavy lifting.

An example authentication flow using Cognito to proxy to SAML IdP integrations

Many IdPs also support using groups for user management. This allows a user to rely on their Active Directory, Okta, or other IdP groups for user RBAC rather than manually configuring access locally within your application.

Fortunately, these group mappings can be passed from the IdP, through Cognito, and to your backend application. AWS wrote a blog post to highlight how Cognito can be used to collect group mappings, but they stopped short of explaining how to actually pass the group mappings to a backend application via the “/userInfo” Cognito endpoint.

Cognito Setup

First, a user pool must be configured in Cognito with the correct settings to support collection of the user’s groups and passing of the profile information.

I won’t walk through the entire process of configuring a user pool, because it is well-documented and not the core focus of this post, but here are a couple things to note:

  • You should set the user’s email address as a required attribute if you plan to map validated users to your backend database.
Creating a new user pool in Cognito

Creating Custom Attributes

To collect the groups from the IdP, you must configure and enable a custom attribute within Cognito. This can be done from the “Attributes” page:

  • I recommend naming the attribute “groups” because let’s not get too fancy.

Enabling the Custom Attribute

Once you create the “custom:groups” attribute, you need to activate it for the app client. Navigate to “App Clients” and then click “Show Details” and then “Set attribute read and write permissions.”

Select the App Client
Expand the attribute permissions
Ensure “Profile” and the new “custom:groups” is set in both “Readable” and “Writable” attributes.

Configure App Client Settings

On the “App Clients” settings page, ensure that “profile” is selected under “Allowed OAuth Scopes.” Without this setting, the additional custom attributes, including “groups,” passed by the IdP, will not be accessible to your backend via the “userInfo” endpoint.

Select “profile” under “App client settings”

Third-Party IdP Setup

Don’t sign out of the Cognito console just yet; we’ll come back to it shortly. But first we need to configure the third-party IdP. I will use Okta as an example for this post, but Active Directory, OneLogin, and Auth0 all have similar configuration options.

Create a New Application

Go through the application setup process to create a new application using the following settings (replace the bold parts with your settings):

  • Single Sign On URL:
    https://YOUR-DOMAIN.auth.us-east-1.amazoncognito.com/saml2/idpresponse

Be sure to configure any other required fields according to your IdP’s documentation.

Attribute Statements

For Cognito to recognize the user and pass the required fields to your backend application, the IdP must pass certain attributes. The names of these attributes are configurable, but they must match across Cognito and the third-party IdP.

Attribute names defined in the IdP must match the attribute names used in Cognito.

Group Attribute Statements

Each IdP handles this a bit differently, but most allow you to pass the group names along using a similarly-named attribute definition. In Okta’s case, you can define groups like this:

Define the group mappings in Okta.

In Okta, I added my user to two groups, “test-group-one” and “test-group-two” for testing purposes.

IdP Metadata

Now, you must get the IdP metadata to create an IdP mapping in Cognito. Most IdPs allow you to export an XML file or provide a configuration URL. Okta provides both options, which can be accessed from the “Sign On” tab of the application.

Select this link to get the XML metadata link.

Back to Cognito

Add an Identity Provider

Now that you have the third-party IdP metadata URL, you can create an identity provider in Cognito. This is done via the “Federation” > “Identity Providers” page. From there, select “SAML” and create a new provider using the URL you obtained from Okta.

Create a new provider using the XML metadata.

Define Attribute Mappings

You now need to tell Cognito which attributes from the provider should be collected and mapped to attributes in Cognito. This is done from the “Attribute mapping” page. Select your new provider from the list and then enter each of the attributes to collect. These should match the same names as entered earlier in Okta. For example, I am collecting the user’s email address under the attribute name “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress”.

Be sure to also define the “groups” attribute and map it to the “custom:groups” user pool attribute.

Define the attribute mappings.

Enable the Identity Provider in the App Client

The final step is to return to the “App client settings” page and enable the new third-party IdP.

Be sure the checkbox next to the IdP is selected and save.

Frontend + Backend Changes

Depending on how your frontend environment is configured (single-page app, JQuery, framework, etc.), you will need to configure the sign in page to match the page defined in the “Callback URLs” portion of Cognito and then handle the “access_token” that is returned. You can also use the AWS Cognito JS SDK to handle this seamlessly in your application.

Once the access_token is retrieved, it can be sent to your backend API or used to fetch the user’s groups directly by passing the authorization header. This call looks like:

curl -X GET https://YOUR-DOMAIN.auth.us-east-1.amazoncognito.com/oauth2/userInfo -H 'authorization: Bearer <access_token>'

The response, if everything worked, will look like:

{
"sub": "abdef0123-aa12-4c41-961d-12abcd1234b4",
"email_verified": "true",
"email": "user@example.com",
"custom:groups": "[test-group-two, test-group-one]"
}

These custom groups (which came from the groups we created in the Okta IdP), can be parsed and used for RBAC within your application.

Geek Culture

Proud to geek out.

Sign up for Geek Culture Hits

By Geek Culture

Subscribe to receive top 10 most read stories of Geek Culture — delivered straight into your inbox, once a week. Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Matt Fuller

Written by

Founder of @CloudSploit , acquired by @AquaSecTeam . Former Infra / Security / Manager @Adobe , @Aviary & @Mozilla intern, @RITtigers grad, @NYC resident

Geek Culture

A new tech publication by Start it up (https://medium.com/swlh).

Matt Fuller

Written by

Founder of @CloudSploit , acquired by @AquaSecTeam . Former Infra / Security / Manager @Adobe , @Aviary & @Mozilla intern, @RITtigers grad, @NYC resident

Geek Culture

A new tech publication by Start it up (https://medium.com/swlh).

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store