Authentication and Authorization with AWS - API Gateway
Dec 29, 2021
Photo by Piyush Wadhwa on Unsplash
AWS Cognito User Pools and Federated Identities can be used to authorize API gateway requests. The methodology is similar to the federated access workflow. This post explores the three ways to allow requests to AWS API Gateway.
User Pool Authorizers
The client signs the user into the User Pool to obtain the JWT tokens. Next, it calls the API with the identity or access token set to the Authorization header. If the API Gateway is configured to use the Cognito User Pool authorizer, the request will be successful. However, the request will fail if the Authorization
header is invalid or not sent.
Once a resource and an HTTP method are set up, one can map the method to an authorizer that uses an existing Cognito User Pool. The Token Source is the HTTP request header for the authorization token.
$ curl -v https://hxe4f81uae.execute-api.ap-south-1.amazonaws.com/stage/resource
{"message":"Unauthorized"}
Without the Bearer authorization (the token source), the API Gateway responds with a 401 UnAuthorized
.
The token is captured with the client code from the previous post.
app.get('/sign-in', async (req, res) => {
console.log(req.query)
try {
const tokens = await requestToken({
code: req.query.code,
authSecret,
hostname: `sayantam-fluent-interface.auth.${region}.amazoncognito.com`,
redirect_uri: 'http://localhost:9000/sign-in'
})
const authorizationToken = tokens['id_token']
console.info(authorizationToken)
res.sendStatus(200)
} catch (_error) {
res.sendStatus(500)
}
})
One can make an authorized request using the client's authorizationToken
.
curl -v -H"Authorization: Bearer $AUTH_TOKEN" https://hxe4f81uae.execute-api.ap-south-1.amazonaws.com/beta/students
With the Bearer token, the API Gateway responds with a 200 OK
.
ID token vs. Access token
The ID token provides an either/or authorization. Optionally, the User Pool authorizer can use OAuth scopes for fine-tuned permissions. In this case, the client should use the access_token
for the Bearer token.
IAM Authorization
IAM permissions control access to an API. The permission would have the following format.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"execute-api:Invoke"
],
"Resource": [
"arn:aws:execute-api:us-east-1:account-id:api-id/*/GET/pets"
]
},
]
}
This permission should be part of the AWS user, group, or role trying to access the API. For example, when using Cognito federated identities, the permission should be part of the role configured for the authenticated user.
Lambda Authorizer
The API Gateway can invoke a Lambda Authorizer (formerly custom authorizer) to authorize a request. The Lambda function returns an IAM policy to allow the API request. This authorization strategy is used when authorization depends on the bearer token or request parameters.
In the case of a token-based authorizer, the input object takes the following structure.
{
"type":"TOKEN",
"authorizationToken":"{caller-supplied-token}",
"methodArn":"arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]"
}
For a request-based authorizer, the input object has type
set to REQUEST
and additional keys. For more information, refer to the AWS documentation page.
The output from an authorizer is an object with the following structure.
{
"principalId": "yyyyyyyy", // The principal user identification associated with the token sent by the client.
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow|Deny",
"Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]"
}
]
},
"context": {
"stringKey": "value",
"numberKey": "1",
"booleanKey": "true"
},
"usageIdentifierKey": "{api-key}"
}
The principal identifier (principalId
) and policy document (policyDocument
) are required attributes. The principalId
is the user identifier in the system - typically, this would be a surrogate key that identifies users. In addition, the object must have the usageIdentifierKey
attribute if the API uses a usage plan. While optional, the API Gateway will pass the context
object to the invoked Lambda function if it is present. The API Gateway can cache the policy and reuse it for subsequent requests till the cache expires beyond the configured TTL.
An API with a Lambda authorizer is invoked with the Bearer token, the same as the invocation in the case of User Pool authorizers.
Comparing Approaches
-
The User Pool authorizer needs no code for authorization making it an ideal choice for most situations. However, it adds the user to the pool on successful authentication, duplicating user information. User pools are charged monthly based on the number of users. This cost may be undesirable unless there is an additional use case for sychronization across the user's devices.
-
The Lambda authorizer is the only choice where the authorization requires custom logic.
-
The IAM authorizer is simple to set up, but signing API requests is non-trivial and only practical when there is a well-tested platform-specific SDK.
Related Posts
Authentication and Authorization with AWS - Federated Access
Nov 21 2021
AWS Cognito Identity Pools provide authenticated users access to AWS resources.
Authentication and Authorization with AWS - Cognito SAML Integration
Nov 14 2021
AWS Cognito integrates with a corporate identity provider such as Active Directory (AD) using SAML.
Authentication and Authorization with AWS - About IAM
Sep 12 2021
Amazon Web Services (AWS) references a dizzying number of concepts, resources, patterns, and best practices to provide a fully managed…
Authentication and Authorization with AWS - Cognito Sign-up and Sign-in
Oct 17 2021
Amazon Web Services (AWS) provides Cognito to delegate authentication and authorization out of applications completely.