
How to create a custom authorizer for AWS API Gateway using serverless Lambda function in Node and .NET Core
Going “serverless” is now becoming one of today’s hot trends for cloud solutions. It’s an agile, modern architectural approach that can help businesses perform faster, better and cheaper.
In serverless cloud solutions, the provider manages the servers and resources to host applications, and charge customers on a flexible “pay for what you use” model. This reduces the need for manual resource provisioning and maintenance, which lets developers focus on value-adding projects.
I first started working with serverless solutions in AWS using Lambda functions, and now I’m utilizing Lambda functions on a regular basis.
Why Use Lambda Functions?
A Lambda function is really a combination of two things:
- A triggering management mechanism for when/why it should run
- A piece of code, which is equivalent of calling a function in a DLL, a web-service through an API, or a script through a cell in Excel
A function runs as your code, so it’s not as public as an API or Windows DLL. They’re linked with dedicated cloud resources (i.e. dedicated RAM and CPU), and payment can be either pay-per-use or pay-per-instance.
A function can also be spun as many times as needed, as opposed to many DLLs that are called once, or APIs for which whatever happens in the background is transparent for the user.
One of the services that integrates well with Lambda functions is the AWS API Gateway. When used together you can build secure serverless APIs.
When using AWS API Gateway, we have many options to secure our APIs. One feature that AWS provides is the ability to create custom authorizers.
What is a Custom Authorizer?
A custom authorizer is basically a Lambda function that you create to provide control access to your API methods. It is a way to secure your APIs by validating data and requests before they are processed.
Custom authorizers use bearer token authentication strategies such as OpenID, OAuth, SAML, or AWS Cognito.
The basic flow of the custom authorizer follows this:
- A client will make a request to your API.
- The API Gateway will determine if a custom authorizer is configured and will invoke it.
- The custom authorizer will then determine if the token is valid and generate a policy.
- The API Gateway will check the policy and will either “allow” or “deny” your request to the API.
Note: Additional flow information can be found here.
In this tutorial, I will show you how to create a custom authorizer, an API Lambda function using .NET Core, and configure the API Gateway to work with your custom authorizer.
Let’s get started.
Prerequisites
Before we begin this tutorial, you will need the following:
- AWS
- Visual Studio 2017 or above
- Visual Studio AWS Toolkit
Now that you have the right tools, let’s build our custom authorizer.
This tutorial will follow 7 steps:
- Create an API Lambda Function using ASP.NET Core Web API
- Deploy the API Lambda Function to AWS
- Test the API Gateway with the API Lambda Function
- Create a Custom Lambda Authorizer Function
- Create an Authorizer for the API in the API Gateway
- Deploy the Authorizer for the API in the API Gateway
- Test the API Gateway
Step 1: Create an API Lambda Function using ASP.NET Core Web API
Let’s start with creating the ASP.NET Core Web API in Visual Studio.
Open Visual Studio and from the project menu create a new project. The dialog below will open.
Go head and click the “AWS Lambda” and select the “AWS Serverless Application (.NET Core)” and name it.
Now select the “ASP.NET Core Web API” Blueprint. This will create a Lambda project template using ASP.NET Core.
Once the project is created you will see the following code structure. Since this is just a basic tutorial, we will use the default API generated code to deploy and test.
The API class we use will be the “ValuesController.cs”, which has basic HTTP Methods “GET, POST, PUT, DELETE”. You can also update the methods with your own logic.
Run the project and test the API locally. Make sure you use the path http://localhost:{port}/api/values to test.
You should see the response below:
Step 2: Deploy the API Lambda Function
Now that the project has been created and is working locally, let’s publish it to AWS. Right click on the project and select “Publish to AWS Lambda…”
Fill out the required profile information and build settings. Then click “Next” to verify addition settings, then click “Publish”.
Step 3: Test the API Gateway with the API Lambda Function
After a successful publish to AWS, the console in AWS will report the status of the stack as “CREATE_COMPLETE” and create the AWS Serverless URL where the API can be accessed.
Now copy the base URL and test in your browser. You should get the same response as you did locally.
Note: Make sure to add your full API path in your URL.
Your API is now successfully running in your AWS API Gateway.
Step 4: Create a Custom Lambda Authorizer Function
With your API running in AWS, let’s create a custom Lambda Authorizer.
Go to Services->Lambda and create a new function. Then input the following:
- Select “Author from scratch”
- Name of your Lambda function
- Runtime: Node.js 6.10
- Select a role or existing role.
- Click “Create Function”
In your Lambda function, scroll down to your Function code editor and add the following code to the index.js file and save your function.
// A simple TOKEN authorizer example to demonstrate how to use an authorization token
// to allow or deny a request. In this example, the caller named 'user' is allowed to invoke
// a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke
// the request if the token value is 'deny'. If the token value is 'Unauthorized', the function
// returns the 'Unauthorized' error with an HTTP status code of 401. For any other token value,
// the authorizer returns an 'Invalid token' error.
exports.handler = function (event, context, callback) {
var token = event.authorizationToken;
switch (token.toLowerCase()) {
case 'allow':
callback(null, generatePolicy('user', 'Allow', event.methodArn));
break;
case 'deny':
callback(null, generatePolicy('user', 'Deny', event.methodArn));
break;
case 'unauthorized':
callback(null, generatePolicy('user', 'Allow', event.methodArn));
break;
default:
callback('Error: invalid token');
}
};
// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
var authResponse = {};
authResponse.principalId = principalId;
if (effect && resource) {
var policyDocument = {};
policyDocument.Version = '2012-10-17';
policyDocument.Statement = [];
var statementOne = {};
statementOne.Action = 'execute-api:Invoke';
statementOne.Effect = effect;
}
}
Note:
One point I want to highlight in the code is the following line:
callback(null, generatePolicy('user', 'Allow', '*'));
The generatePolicy method has the ‘*’ parameter passed in. This is a wildcard to cover all methods in the policy, since the API is configured as a Lambda proxy. This is very important, because you will run into issues for different API method requests if the wildcard is not used.
In addition, when caching is enabled on the authorizer, you will avoid “User is not authorized to access this resource” errors.
When you only want to use a specific method (i.e. GET) you want to use the ‘event.methodArn’ instead of the wildcard.
Step 5: Create an Authorizer for the API in the API Gateway
Let’s now go back to the API Gateway service and select your API and then select “Authorizers”. Here you will create a new authorizer. Fill in the following and click “Create”:
Name: {authorizer name}
Type: Lambda
Lambda Function: {Select the name of the one you create in the previous section}
Lambda Event Payload: Token
Token Source: {Token Header you want to use to test}
Authorization Caching: {optional if you want caching}
Now select “Resources” and click on “ANY”. Here you will see the Method Execution information and you will also notice in the “Method Request” box has no Auth. You will now need to click on “Method Request”.
In the “Method Request”, you will now select the “Authorization” that you created. Make sure you click on the circle check box so it will save your settings.
Step 6: Deploy the Authorizer for the API in the API Gateway
Go to the “Actions” drop down and select “Deployment stage” and click “Deploy”.
Step 7: Test API Gateway
We are now ready to test our API and verify the custom authorizer is working. Go to your API’s published URL and test it.
You should get an unauthorized message, which is good because we know the authorizer has been executed and is validating if the header is provided.
Let’s add the header “test-token” to our request. You can use any modify header browser plugin to assist you with this or a popular tool like Postman.
Once you add the header, you can now make the same request again and see a successful response.
Finished
Now that you have completed this tutorial, you can go on to create your own custom authorizer to perform secure token-based authorization in AWS. I hope these steps help you on your next authorizer.
For more advanced authorizers, you can also integrate with third party identity service providers such as Auth0. I’ll cover these in my next tutorial.
Learn more:
Securing AWS API Gateway Endpoints with Custom Authors
How API Gateway Resource Policies Affect Authorization Workflow