AWS Public Sector Blog
Using Login.gov as an OIDC IdP with Amazon Cognito user pools
As federal agencies strive to enhance digital services and create a seamless customer experience, integrating robust identity and access management (IAM) solutions has become paramount. Amazon Cognito, a robust user identity management service offered by Amazon Web Services (AWS), provides a secure and scalable solution for managing user authentication and authorization. When combined with Login.gov, a trusted identity platform developed by the U.S. General Services Administration (GSA), federal agencies can unlock a powerful combination that streamlines user access while maintaining the highest levels of security and compliance. This integration empowers agencies to deliver a user-friendly experience, enabling citizens to access multiple government services with a single set of credentials, reducing friction and improving overall satisfaction with digital interactions.
Login.gov delivers an identity platform for public users interacting with government websites by combining maximum security standards, open-source technologies, and AWS. The goal is simple: one username and one password for every public user who interacts with government websites. To accomplish this, Login.gov merges a user-focused design with the highest security standards from the National Institute for Standards in Technology (NIST) and the Cybersecurity National Action Plan. The team also committed to making Login.gov an open project that leverages key technologies—like Amazon Elastic Compute Cloud (Amazon EC2), Amazon Relational Database Service (Amazon RDS), and Amazon Simple Storage Service (Amazon S3)—to build a highly-available and scalable platform.
Login.gov on AWS
While the performance of the platform is critical, security is paramount to its success. Login.gov is leveraging AWS services to give the platform the strongest security possible. This includes using AWS to rapidly iterate and keep up with the latest technologies and current cyber threats.
The Login.gov team can quickly set up new environments to validate patches, push changes, or test new solutions. Additionally, Login.gov is leveraging key AWS services, like Amazon CloudWatch and AWS Key Management Service (KMS), to keep their platform secure. KMS is critical in deploying their vault and allowing data encryption unique to every individual.
Login.gov not only makes accessing government websites easier, but it also aids federal agencies in deploying identity solutions. With the Login.gov team managing the system, federal agencies no longer have to spend time, money, and resources developing and maintaining their own identity platform. This means federal agencies can spend fewer resources on developing identity solutions and more resources on their missions.
In this post, we discuss how to federate Amazon Cognito authentication to Login.gov OpenID Connect (OIDC) identity provider (IdP) using private JSON Web Token (JWT) client authentication with Amazon API Gateway and AWS Lambda proxy integration. The advantage of using serverless technologies for this solution allows separating out the undifferentiated heavy lifting of managing servers, patching, etc.
This post builds upon a previous post in the AWS Security Blog, Use private key JWT authentication between Amazon Cognito user pools and an OIDC IdP, which shows how to use private key JWT authentication between Amazon Cognito user pools and an OIDC IdP to enforce additional security measures to meet security compliance requirements. In addition to private key JWT, Login.gov also supports Proof Key for Code Exchange by OAuth Public Clients (PKCE) as an extension to the OIDC authorization code grant flow, which is preferred for native mobile apps, but PKCE is not covered in this post.
Solution overview: Customizations required to federate OIDC private key JWT authentication with Login.gov
Login.gov supports private_key_jwt
as the authentication method for clients who want to federate to Login.gov using OIDC. It also requires certain parameters to be passed to the authorization endpoint. To federate from Amazon Cognito to Login.gov, a proxy must be used to support the following Login.gov requirements:
- a) custom parameters to authorization endpoint, and
- b)client assertion JWT signed with client’s private key for token exchange.
Amazon Cognito user pool can federate to external third-party identity providers using OpenID Connect. In this federation flow, the external IdP returns an authorization code to Amazon Cognito oauth2/idpresponse
endpoint. Amazon Cognito then exchanges this code with a token from external IdP’s token endpoint using either a pre-shared secret (client_secret
) or a JWT token (private_key_jwt
). Token exchange happens from the back-channel connection (i.e., not exposed to user-agent or client application).
Amazon Cognito supports token exchange using client_secret_post
which means the client_secret is sent in the body of the POST request to the external IdP’s token endpoint. However, Login.gov and some identity providers require other methods such as client_secret_basic
(secret in authorization header) or a method that doesn’t include any secret but, rather, requires a token that is signed using a private key and can be verified using a pre-shared public key (private_key_jwt
). Login.gov supports both private_key_jwt and PKCE but does not support client_secret_basic for security reasons.
Figure 1 shows an overview of the architecture and the steps in the login flow to request an authorization code and signed JWT token request to Login.gov.
These are the details for all 10 steps from Figure 1:
- Authorization request: Login.gov user makes the initial authorization request to Amazon Cognito integrated application via API Gateway Lambda proxy.
- Authorize Lambda: When Amazon Cognito calls the API endpoint, it automatically invokes a Lambda function to extend the authorization request with Login.gov required parameters.
- Authorization code: Lambda makes a custom Identity Assurance Level (IAL) authorization request to the Login.gov
/openid_connect/authorize
endpoint. After the user successfully authenticates to Login.gov, Login.gov redirects to Amazon Cognito/oauth2/idpresponse
endpoint with a response that includes a unique authorization code. - Token request: Amazon Cognito-hosted user interface (UI) makes a token request with the Login.gov provided authorization code via API Gateway Lambda proxy.
- Token Lambda: When Amazon Cognito calls the API Gateway endpoint for the token request, it automatically invokes a separate Lambda function to handle the token exchange with Login.gov.
- Get private key: The Lambda function retrieves the private key from AWS Secrets Manager.
- Sign JWT: The Lambda function creates and signs the client assertion JWT with the private key from Secrets Manager.
- ID and Access tokens: The Lambda function makes the token request to the Login.gov
/api/openid_connect/token
endpoint with the signed client assertion JWT. After successful client assertion validation using the pre-shared public key, Login.gov returns a uniqueid_token
andaccess_token
as JSON objects. - Return id_token and access tokens: The Lambda function returns the response with the unique id and access tokens, which Amazon Cognito uses to create or update the user in the user pool.
- Verify claims: The Amazon Cognito-hosted UI validates the
id_token
using Login.gov public key certificate published at Login.gov/api/openid_connect/certs jwks_uri
Then Amazon Cognito-hosted UI validates theaccess_token
by attempting a request to Login.gov/api/openid_connect/userinfo
endpoint using theaccess_token
to retrieve user attributes.
How to configure Amazon Cognito, API Gateway, and Lambda to integrate with Login.gov using OIDC private key JWT authentication
The following sections walk you through how to configure Amazon Cognito federation to Login.gov as an OIDC Idp using API Gateway Lambda proxy integration for “authorize” and “token” endpoints.
Prerequisites
- Register with Login.gov. To test integration between Login.gov and your application using Amazon Cognito user pools, get set up with a Login.gov sandbox account and create a federation client application for testing purposes only.
Note: You will have to add your Amazon Cognito user pool domain URL with the /oauth2/idpresponse
endpoint (for example: https://<mydomain>.<region>.amazoncognito.com/oauth2/idpresponse) to Login.gov as a valid redirect URI. Login.gov will not redirect to URIs after authentication unless they are listed in the Login.gov client application.
- Create PEM-encoded public/private keys. You need the public certificate during the client application creation in Login.gov and the private key to sign client assertion JWT for token exchange as indicated in the following sample code using openssl for the token proxy. The private key is securely stored and managed in Secrets Manager.
openssl req -nodes -x509 -days 365 -newkey rsa:2048 -keyout private.pem -out public.crt
Note: It’s recommended to rotate the private and public key pair regularly per your compliance and security requirements.
Authorize Lambda for custom authorize endpoint
Federation from Amazon Cognito to Login.gov redirects to the API Gateway Lambda proxy authorization endpoint. This endpoint returns a redirect response to Login.gov authorization endpoint with additional required parameters. Login.gov will redirect back to the provided Amazon Cognito user pool URL with a unique authorization code
in the authorization response if authorization is successful. An error message is returned if authorization is unsuccessful.
The details of the Authorize Lambda function logic can be broken down into the following:
- Receive original request from Amazon Cognito redirect to API Gateway Lambda proxy authorization endpoint.
- Add the additional required parameters for authorization in the request parameters.
- Redirect original request with additional parameters to Login.gov authorization endpoint.
Token Lambda for custom token endpoint
Amazon Cognito uses a custom token endpoint proxy to exchange the authorization code
for id_token
and access_token
. The client assertion JWT is signed with the private key from Secrets Manager to request the tokens from the Login.gov token endpoint. Token exchange is not exposed to user-agent or client application, and handled by the token Lambda function requesting the token from Login.gov.
The Token Lambda function logic is the same as described in the previous post in the AWS Security Blog, Use private key JWT authentication between Amazon Cognito user pools and an OIDC IdP.
Sample API Gateway Lambda proxy integration for authorization and token endpoints
After creating the two Lambda functions, create an API Gateway Lambda proxy API with a dedicated route for the authorize (for example, /authorize) endpoint Lambda function and another route for the token (for example, /token) endpoint Lambda function. Figure 2 is a screenshot of this step.
You then need to deploy the API and take the execution URLs and add them as the authorize and token endpoints in the IdP configuration in Cognito user pool in the next section.
Sample Amazon Cognito user pool configuration
Add Login.gov as the OIDC identity providers to Amazon Cognito user pool. Use these 10 configurations for a sample application for a Login.gov test sandbox account. Figure 3 that follows is a screenshot of OIDC IdP configuration for a Login.gov sandbox account using Amazon Cognito:
- Provider name: Friendly name for Login.gov OIDC provider.
- Client ID: Login.gov-provided issuer unique string to identify your app in Login.gov. This is registered with Login.gov IdP in advance as part of Login.gov client app setup as outlined in the Prerequisites section above.
- Client secret: <blank>
- Authorized scopes: User attributes to exchange between Login.gov OIDC IdP and your app (for example, openid email).
- Attribute request method: GET
- Issuer URL: Login.gov OIDC issuer URL
- Authorization endpoint: API Gateway Lambda proxy URL endpoint which invokes the authorize Lambda function.
- Token endpoint: API Gateway Lambda proxy URL endpoint which invokes the token Lambda function.
- UserInfo endpoint: Login.gov user info endpoint used to retrieve Login.gov user attributes.
- Jwks_uri endpoint: Login.gov public key certificate endpoint used to verify Login.gov signed JWTs such as the
id_token
.
Deploy a demo
To deploy an example of this solution, see our GitHub repository [coming soon]. You will find the prerequisites and deployment steps there, as well as additional in-depth information.
Summary
In this post, you saw how to federate Amazon Cognito user pools with Login.gov OIDC identity provider using private JWT authentication. By leveraging serverless services like Lambda and API Gateway, the solution separates the undifferentiated heavy lifting of managing servers and enables custom logic to meet Login.gov’s requirements for authorization and token exchange.
The architecture involves Lambda functions proxying the authorize and token requests, signing the client assertion JWT with a private key from Secrets Manager, and exchanging the authorization code for an ID token and access token from Login.gov. This serverless approach provides a secure and scalable way to integrate Cognito with Login.gov while adhering to compliance requirements around private key JWT authentication.
If you have feedback about this post, submit comments in the Comments section below. If you have questions about this post, start a new thread on AWS re:Post for Amazon Cognito User Pools or contact AWS Support.