Introduction
An API that is exposed to the public must admit only callers whose identity has been confirmed and who are permitted to perform the requested action. This guide explains how such protection is built with Amazon Cognito and Amazon API Gateway. Readers who are new to these services should first read the guides on Amazon Cognito and Amazon API Gateway.
What is the pattern?
The pattern combines a Cognito user pool, which authenticates users and issues tokens, with API Gateway, which validates those tokens before a request is admitted. Validation is performed by an authorizer, which is a component that checks the identity and permissions of a caller. Two forms of authorizer are available. A Cognito authorizer validates a token from a user pool without custom code, and a Lambda authorizer runs a function that applies custom logic.
Why does it exist?
Verifying a caller correctly is difficult and easy to get wrong. Tokens must be validated, expired tokens must be refused, and permissions must be enforced. If each API were to build this from the beginning, the risk of a security flaw would be high. The pattern exists so that authentication is provided by Cognito and validation is provided by API Gateway, which leaves the backend to enforce only the decisions that depend on the data.
How it works
The user signs in to the user pool and receives an ID token and an access token. On each request, the client sends a token in the Authorization header. API Gateway invokes the authorizer, which verifies the signature, the expiration time, and the audience of the token. If the token is valid, the request is forwarded to the backend, most often a Lambda function, together with the claims from the token.
The backend then performs authorization. A user can be placed in a Cognito group, and the group appears as a claim in the token. A scope is a value in an access token that states what the token is permitted to do. The backend reads these claims and permits or refuses the action accordingly.
Architecture diagram
Advantages
- Standard validation. Tokens are checked at the gateway without custom code.
- Separation of concerns. Cognito authenticates, the gateway validates, and the backend authorizes.
- Scalable. The stateless token model requires no session store.
- Fine control. Groups and scopes allow permissions to be expressed precisely.
Disadvantages
- Configuration. The user pool, the authorizer, and the backend must all be set up correctly.
- Token handling. The client must obtain, store, and refresh tokens safely.
- Two layers of authorization. Both the token contents and the backend logic must agree.
Common use cases
- A web or mobile application that calls a private API.
- An API in which different users are permitted different actions.
- A service that must confirm the identity of every caller before responding.
Best practices
- Tokens should be validated at the gateway so that invalid requests never reach the backend.
- Authorization that depends on the data should be enforced in the backend, not only in the client.
- Permissions should follow the principle of least privilege, which is the practice of granting only what is required.
- Short token lifetimes and encrypted connections should be used throughout.
Common mistakes
- Authorization is enforced only in the client, which a caller can bypass.
- Tokens are accepted without validation.
- Overly broad permissions are granted to a group or a scope.
- The backend trusts the identity supplied by the client rather than the validated token claims.
Related AWS services
- Amazon Cognito authenticates users and issues the tokens.
- Amazon API Gateway validates the tokens through an authorizer.
- AWS Lambda runs the backend and enforces authorization.
- AWS Identity and Access Management governs the permissions of the services involved.
Frequently Asked Questions
- How does API Gateway validate a Cognito token?
- A Cognito authorizer is attached to the API. The token in the Authorization header is checked against the user pool, and the signature, expiration, and audience are verified. The request is admitted only if the token is valid.
- What is the difference between authentication and authorization in this design?
- Authentication confirms who the caller is, established by the valid token. Authorization decides what the caller may do, determined from the groups or scopes in the token and enforced by the backend.
- What is the difference between a Cognito authorizer and a Lambda authorizer?
- A Cognito authorizer validates a user pool token with no custom code. A Lambda authorizer runs a function that can apply custom logic, used when validation must go beyond the standard check.
- How is access limited by role?
- A user can be placed in a Cognito group that appears as a claim in the token. The backend reads this claim and permits or refuses the action. Scopes can be used in a similar way.
- Should the backend re-check the caller even after the gateway validates the token?
- Yes. The gateway confirms that the token is valid, but the backend should still enforce what the specific caller may do for the specific resource.
This article is the summary. The book is the full, continuously updated reference: authorizers, groups and scopes, Lambda triggers, token validation, and securing a real website.
View the book