Cognito User Pools can authenticate users for your API Gateway, but it’s not just about basic login; it’s about offloading user management and authorization entirely to a managed service, allowing your API Gateway to focus solely on routing and execution.

Let’s see it in action. Imagine a simple API Gateway endpoint /users/{userId} that’s protected by Cognito.

// Example Request to API Gateway with Cognito Authorizer
GET /users/12345 HTTP/1.1
Host: your-api-id.execute-api.us-east-1.amazonaws.com
Authorization: Bearer eyJraWQiOiJ...<your-cognito-id-token>

When this request hits API Gateway, the Cognito authorizer intercepts it. It takes the Authorization header, validates the JWT (JSON Web Token) against your Cognito User Pool’s public keys, checks the token’s expiration, and verifies that the iss (issuer) and aud (audience) claims match your Cognito User Pool and API Gateway’s client ID, respectively. If all checks pass, API Gateway forwards the request, injecting claims from the Cognito token into the request headers or body (your choice) for your backend to consume.

The problem this solves is fundamental: how do you secure your APIs without building and maintaining your own user authentication and management system? Cognito User Pools provide a fully managed service that handles user registration, sign-in, multi-factor authentication (MFA), password recovery, and token generation. API Gateway integrates seamlessly with this, acting as the gatekeeper.

Here’s how it works internally:

  1. User Sign-up/Sign-in: Users interact with your application’s frontend, which uses the AWS Amplify library (or direct Cognito SDK calls) to sign up or sign in with your Cognito User Pool.
  2. Token Issuance: Upon successful authentication, Cognito issues three types of JWTs: an ID token, an access token, and a refresh token. The ID token contains user profile information, the access token is used for authorizing API requests, and the refresh token is used to obtain new ID and access tokens without requiring the user to re-authenticate.
  3. API Gateway Configuration: In API Gateway, you configure a "Cognito User Pools Authorizer." You specify your User Pool ID and the App Client ID that your frontend application uses.
  4. Authorization Flow: When a client makes a request to a protected API Gateway endpoint, it includes the ID token (or access token, depending on your configuration) in the Authorization header, typically as a Bearer token.
  5. Token Validation: API Gateway’s Cognito authorizer receives the token. It performs several checks:
    • Signature Verification: It fetches the public keys from your User Pool’s .well-known/jwks.json endpoint and verifies the token’s signature.
    • Expiration Check: It ensures the token has not expired.
    • Issuer (iss) Claim: It verifies that the token was issued by your specific Cognito User Pool.
    • Audience (aud) Claim: It checks that the token was intended for the API Gateway client (your App Client ID).
  6. Request Forwarding: If the token is valid, API Gateway allows the request to proceed to your backend integration. It can also map claims from the token (like sub for user ID, email, cognito:username, custom attributes) into request headers (e.g., x-cognito-username) or the request body, making user identity available to your application logic.

Let’s look at a concrete API Gateway authorizer configuration snippet. In the AWS console, or via CloudFormation/Terraform, you’d define an authorizer like this:

MyCognitoAuthorizer:
  Type: COGNITO
  IdentitySource: method.request.header.Authorization
  ProviderARNs:
    - arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_xxxxxxxxx

Here, IdentitySource tells API Gateway where to find the token (the Authorization header). ProviderARNs points to your specific Cognito User Pool.

The most surprising true thing about using Cognito User Pools with API Gateway is how easily you can gain fine-grained access control based on user attributes or groups directly within API Gateway’s authorizer configuration, without writing any code in your backend. You can define a context variable in your authorizer that maps a specific claim (like a custom attribute tenant_id) to a variable that API Gateway then injects into the backend request. For example, you could configure the authorizer to extract a custom:tenant_id claim from the JWT and make it available as request.stageVariables.tenantId. This allows your backend to immediately know which tenant the user belongs to, without needing to re-parse the token itself.

The next concept you’ll likely encounter is how to handle authorization beyond just "is this user logged in?" – specifically, implementing role-based access control (RBAC) or attribute-based access control (ABAC) using Cognito groups and custom attributes.

Want structured learning?

Take the full Apigateway course →