Reuse Authorizers Across AWS API's
Check out this tutorial on reusing authorizers across different APIs in AWS, using API Gateway and Lambda.
Join the DZone community and get the full member experience.
Join For FreeTechnology has seen tremendous growth in recent years. This growth has enabled finding solutions to a problem to be very easy. Though finding solutions are easy, getting the right solution requires skill, knowledge, and effort. In this article, we will explore how we can achieve an authorizer across multiple APIs in AWS using API Gateway & Lambda.
Authorizers are the first line of defense to keep your API from abuse. With OAuth, it normally is validating a token to ensure that the user is allowed to access the resource that is being protected. A token could be generated with many different scopes, so it would be one of the authorizer's responsibility to validate if the token has been generated with the appropriate scope that is required for it to consume the resource. This extra validation makes it difficult to share authorizers across multiple API's.
Authorizers can be created in two different flavors: token and request.
Token-based lambda authorizers receive the below object as its event to process the authorization request:
{
"type":"TOKEN",
"authorizationToken":"<caller-supplied-token>",
"methodArn":"arn:aws:execute-api:<regionId>:<accountId>:<apiId>/<stage>/<method>/<resourcePath>"
}
For request-based lambda authorizers, lambda receives the event object as below:
{
"type":"REQUEST",
"methodArn":"arn:aws:execute-api:us-east-1:xxxx:xxxx/test/GET/request",
"resource":"/request",
"path":"/request",
"httpMethod":"GET",
"headers":{
...
},
"queryStringParameters":{
"QueryString1":"queryValue1"
},
"pathParameters":{
},
"stageVariables":{
"StageVar1":"stageValue1"
},
"requestContext":{
"path":"/request",
"accountId":"xxxxx",
"resourceId":"xxxx",
"stage":"test",
"requestId":"...",
"identity":{
"apiKey":"...",
"sourceIp":"..."
},
"resourcePath":"/request",
"httpMethod":"GET",
"apiId":"xxxx"
}
}
For us to make the authorizer generic/shared, we need to have the valid scopes for the token as part of an event received by the authorizer. The authorizer lambda function itself cannot be configured generic, because doing so would make the API very un-secure.
We are trying to solve the above problem of re-using authorizer lambdas that often needs a list of scopes that have to be validated, as shown in below figure:
There are two approaches to solving this problem:
Approach 1
We will be using a request-based lambda function as the authorizer, along with stage variables. Stage variables can be used to provide a custom configuration that is required for the authorizers. A list of valid scopes of the API will be passed in one of the stage variables. Authorizers can read this from the request and validate the token along with the scope.
If you are using serverless for deployment, you can make use of "serverless-plugin-stage-variables" to add stage variables to API.
Note: When you are updating an existing API with stage variables, the serverless plugin could run into issues like "stage already exists." If this happens, delete the CloudFormation stack and redeploy again.
Approach 2
We will be using again a request-based lambda function as the authorizer. However, this lambda function will look up a configuration (based in dynamodb, firebase, etc ) to retrieve the list of valid scopes for a given API. To uniquely identify the API, we will use the "requestContext" that is sent along with the event. We can use a combination of "requestPath," "path" and "apiId" attributes within "requestContext" to determine the API uniquely.
Note: If you are using API Gateway Custom Domain Names, the "path" attribute within "requestContext" will contain the entire context, including the name defined in API Gateway Custom Domain.
If the API has path parameters, the requestPath would not identify the API uniquely, using apiId could, most likely, help.
Conclusion
The AWS API Gateway itself doesn’t provide ways to exclusively configure authorizers. Both the above approaches feel like a workaround than an exact solution to the problem. Nevertheless, it works and it deserves to be part of the best practices that could be followed.
Opinions expressed by DZone contributors are their own.
Comments