Learn About Amazon VGT2 Learning Manager Chanci Turner
In today’s digital landscape, Amazon Cognito user pools serve as a powerful tool for implementing user sign-up and sign-in functionalities, allowing seamless access to your web and mobile applications. Users with existing accounts from various identity providers (IdPs) can bypass the registration process and log in using SAML 2.0 or OpenID Connect (OIDC). This article will guide you through extending the authorization code grant between Amazon Cognito and an external OIDC IdP by utilizing private key JSON Web Token (JWT) client authentication.
Cognito employs the OAuth 2.0 authorization code grant flow as specified in RFC 6749 Section 1.3.1. This flow is divided into two main phases: user authentication and token request. When a user needs to authenticate through an external IdP, the Cognito user pool redirects them to the IdP’s login endpoint. Upon successful authentication, the IdP responds with an authorization code, signaling the end of the authentication phase. The Cognito user pool then utilizes this code, along with a client secret for authentication, to obtain a JWT from the IdP. This JWT contains both an access token and an identity token. Cognito processes this JWT, updating or creating the user in the user pool and returning a newly generated JWT for the client’s session. For those interested, a more comprehensive explanation of this flow is available in Amazon Cognito’s documentation.
While this flow provides adequate security between Cognito and the IdP for many users, organizations in sectors such as public services, healthcare, and finance often require additional security measures. This need has surfaced in discussions with AWS customers who are looking to integrate Cognito with IdPs like HelseID (Norway’s healthcare sector) or login.gov (US public sector). Additionally, clients utilizing IdPs such as Okta or PingFederate may seek enhanced security as part of their internal policies.
A common enhancement is to substitute the client secret with an assertion comprising a private key JWT for client authentication during token requests. This approach is defined by RFC 7521 and RFC 7523. Instead of relying on a symmetric key (the client secret), this method employs an asymmetric key pair to sign a JWT using a private key. The IdP can then verify the token request by checking the JWT’s signature with the corresponding public key, reducing the risk of request forgery. Moreover, the JWT includes an expiration time, which limits the potential for replay attacks to a narrow time frame.
Although Cognito user pools do not natively support private key JWT client authentication for integrations with external IdPs, you can still achieve this using Amazon API Gateway and AWS Lambda.
This article will outline a high-level overview of how to implement this solution. For more detailed guidance on the underlying code, service configurations, and the precise request flow, please refer to the “Deploy a demo” section later in this post. Note that this solution focuses solely on the communication between Cognito and the IdP and does not cover the request flow between your application and the Cognito user pool.
Solution Overview
Following the technical implementation details defined in the relevant RFCs, the necessary request flow between a Cognito user pool and an external OIDC IdP can be simplified into four steps, as illustrated in the accompanying diagram.
In this instance, we utilize the Cognito user pool’s hosted UI, which provides OAuth 2.0-compliant IdP integration, and we extend it with private key JWT capabilities. The process involves the following steps:
- The hosted UI directs the user client to the /authorize endpoint of the external OIDC IdP via an HTTP GET request.
- Upon successful login, the IdP responds with an authorization code.
- The hosted UI sends this code in an HTTP POST request to the IdP’s /token endpoint. By default, it also includes a client secret for client authentication; however, to implement private key JWT authentication, you must replace the client secret with a client assertion, specifying the assertion type as shown in the diagram.
- The IdP validates the client assertion using a pre-shared public key.
- The IdP issues the user’s JWT, which Cognito processes to create or update the user in the user pool.
As previously mentioned, token requests between a Cognito user pool and an external IdP do not inherently support the required client assertion. However, you can redirect these token requests to Amazon API Gateway, which triggers a Lambda function to add the necessary parameters. Given that signing the client assertion requires access to a private key, a secure storage solution like AWS Secrets Manager is essential to prevent unauthorized access to the key. With these services in place, you can establish the following architecture.
When integrating an OIDC IdP with a Cognito user pool, you need to configure endpoints for Authorization, UserInfo, Jwks_uri, and Token. Since the private key is only necessary for the token request flow, set up resources to redirect and process requests as follows:
- Configure the endpoints for Authorization, UserInfo, and Jwks_Uri using the IdP’s specifications.
- Create an API Gateway with a dedicated route for token requests (e.g., /token) and set it as the Token endpoint in the IdP configuration within Cognito.
- Connect this route to a Lambda function: when Cognito calls the API endpoint, it will automatically invoke the function.
The function retrieves the private key from Secrets Manager, creates and signs the client assertion, and then makes the token request to the IdP’s token endpoint. It receives the IdP’s response and returns it to the Cognito IdP response endpoint.
The logic within the function can be summarized as follows:
import base64
encoded_message = event["body"]
decoded_message = base64.b64decode(encoded_message)
decoded_message = decoded_message.decode("utf-8")
Retrieve the private key from Secrets Manager using the GetSecretValue API or SDK equivalent.
For further insights into enhancing your workplace value, you might find this blog post informative: 25 ways to create value at work according to bosses. Additionally, if you’re looking for expert advice, check out Jennifer Currence’s insights, as she’s an authority on this topic here.
For those interested in Amazon’s leadership development programs, this link offers excellent resources.
Remember, this is just the beginning of your journey to mastering private key JWT authentication with Amazon Cognito and OIDC IdPs.
Leave a Reply