Introduction
In the previous post, we talked about how to configure the AWS ALB
listener for Entra ID OIDC authentication. We noticed that the ALB does not forward the ID token that contains the
user’s group memberships to the backend. The ALB forwards the access token as x-amzn-oidc-accesstoken. It generates
new JWTs as headers called x-amzn-oidc-data and x-amzn-oidc-identity that contain the user claims from the user info
endpoint and the subject field (sub) respectively. The Entra ID user info endpoint does not return any group memberships
of the user and hence the need for some alternatives to get the groups claim. We discussed using the Graph API to get
the groups in the last post, and today we will discuss how to use Cognito configured with Entra ID as the OIDC provider
for the ALB.
Configure ALB Entra ID OIDC Federation with Cognito
Below is the terraform code snipper to create a new Cognito User Pool with an Entra ID OIDC client. In addition, we
map the attributes that we want to forward to the backend application to a new custom attribute. We mapped the most
important claims such as sub, name, email, groups, and roles to custom attributes. Since Entra ID is used to
manage the users, we should disable the user sign-up feature in Cognito when we create the user pool.
| |
Note that there is a 2048 char limit for mapped Cognito custom attributes!
After creating all the Cognito resources, we can now configure the ALB listener to use Cognito for OIDC authentication. The below is the terraform code snippet for configuring the HTTPS listener:
| |
Don’t forget to update the app registration call back URIs with the auth one from Cognito!
Now the ALB listener is configured to use Cognito for OIDC authentication, and Cognito is configured to use Entra ID.
Once a user authenticates, the ALB listener forwards the request to Cognito. Cognito then redirects the user to Entra
ID. Once the user enters their credentials correctly, Entra ID issues the tokens and redirects the user back to Cognito.
Cognito maps the custom attributes that we configured in the Cognito user pool to the custom attributes that we want to
forward to the backend application. The ALB listener now adds these custom attributes to the x-amzn-oidc-data header
JWT that will be forwarded to the backend application. Below is the ALB Cognito authentication sequence diagram:
sequenceDiagram
participant User as User (Browser)
participant ALB as AWS ALB (HTTPS Listener)
participant Cognito as Cognito User Pool
participant Entra ID as Entra ID (Azure AD)
participant Backend as Backend (Application)
User ->> ALB: Request resources
ALB ->> Cognito: Cognito OIDC authentication
Cognito ->> Entra ID: Entra ID OIDC authentication
Entra ID -->> Cognito: ID and Access Tokens from Microsoft
Cognito -->> ALB: Cognito tokens with group memberships such as "custom:roles"
ALB ->> Backend: ALB x-amzn-oidc-* tokens now contain group memberships via custom:* attributes
Backend -->> User: Authorize user according to group memberships
Note right of Cognito: Cognito custom attributes mapping:<br/>"custom:roles" = "roles"<br/>"custom:groups" = "groups"<br/>etc. (additional custom attributes)
Architecture Diagram
Here is the architecture diagram for the above setup:
- The user sends an HTTPS request to the ALB listener.
- The ALB checks the encrypted AWSELBAuthSessionCookie to see if the user is authenticated.
- If the user is authenticated and the credentials have not expired, the ALB forwards the request to the backend application.
- If the user is not authenticated, the ALB redirects to Cognito.
- Cognito redirects the user to Entra ID.
- Entra ID issues the ID and access tokens and redirects the user back to Cognito.
- Cognito issues new ID and access tokens where the custom attributes that we configured in the Cognito user pool are mapped to the Microsoft ID token claim that we want to forward to the backend application.
- The ALB listener adds these custom attributes to the
x-amzn-oidc-dataheader JWT that will be forwarded to the backend application. - The ALB forwards the request to the backend application.
Debugging ALB Headers
We mapped one of the ALB target groups to a Lambda function that prints the headers that are forwarded to the backend application. The below is the Lambda function code:
| |
Here is the browser Lambda function response containing all the headers that are forwarded to the backend application:
| |
Let’s check the x-amzn-oidc-data header to see if the custom attributes that we mapped from the Microsoft ID token
claims are forwarded to the backend application. Here is a decoded x-amzn-oidc-data JWT:
| |
All the custom attributes that we mapped from the Microsoft ID token claims are now forwarded to the backend application. We used Cognito as a federated OIDC provider for the ALB listener.
Conclusion
In this post, we discussed how to configure the AWS ALB listener to use Cognito for OIDC authentication and how to configure Cognito to map custom attributes from the Microsoft ID token claims to be forwarded to the ALB tokens. This solved the problem of the disappearing ID token along with its group memberships claim that can be used by the backend for AuthZ as described in the first post.
Microsoft ID token with claims
|
| (e.g. groups)
V
Cognito idToken with custom attributes mapping
|
| (e.g. "custom:groups" = "groups")
V
ALB x-amzn-oidc-data token with custom:groups and other custom attributes
|
| x-amzn-oidc-* tokens forwarded
V
Backend application receives all mapped custom attributes
References: