
Authorization
An API Gateway in production endures traffic. It would be naive to assume that all of the traffic sources have benevolent intentions. APIs have to be protected through various mechanisms.
API keys impart the first line of defense, but they don't provide any authentication or authorization functionality:
- Authentication: It is the process of verifying identity. For example, you can authenticate that a client of an API is actually who they claim they are
- Authorization: It is the process of applying access controls to an authenticated client. Both of these are critical pillars of a production-grade API system. In this section, we will look at how API Gateway can be protected/authorized
- Using Cognito pools: As seen previously, AWS Cognito is the identity and access management offering of AWS. One can create a user pool that can be considered an Identity Provider (iDP)
Applications that leverage this setup have to sign in (authenticate) users against a user pool and obtain an identity (ID) token, access token, and refresh token. This is the standard OpenID Connect (OIDC) specification. The identity token is used to authorize API calls based on the user's identity, and the access token is used to authorize API calls. This is a turnkey solution for most apps that drive their user identity management with Cognito, and it is often a great choice. If the user pool is set up and consumed by an application properly, the only configuration that has to be done is choosing the header name in the request that the app sends for authorization, the API Gateway and Cognito integration does the magic.
The official documentation outlines this approach elegantly.
- Using Lambda authorizers: Using Cognito pools as authorizers to the API Gateway is elegant, but it requires that the resources be modeled properly; otherwise, it might not work as expected. For a more flexible approach, one can roll up their own custom authorization mechanism, using Lambda functions
In this approach, the client (or app) sends a bearer token, which has the necessary information to verify the claims of the owner. This token can be passed via a header, request parameters, the stage env variables, and more.
Whenever the API Gateway that is configured to authorize via Lambda authorizers receives an API call, a Lambda function is triggered and the authorizer verifies the claim and returns a principal (the user) and AWS policy, dictating whether the API call should be passed through (allowed) or not (unauthorized).
Essentially, one is rolling up their own authorization scheme. This requires in-depth knowledge of standard specifications, like JWT, OpenID Connect, OAuth2.0, and the AWS concept of policies.
The following diagram depicts this functionality on a high level: