AppSync Lambda authorizers via new Amplify Custom Resources
Published: 2021-11-18 15:56:36

[Amplify](https://aws.amazon.com/amplify/) and [AppSync](https://aws.amazon.com/appsync/) allow customers to consume a fully managed GraphQL API endpoint in minutes and gracefully handle authorization. This article shows how you can leverage the newly recently introduced [AWS Custom Resources](https://docs.amplify.aws/cli/custom/cdk/) to add the new [AWS Lambda](https://aws.amazon.com/about-aws/whats-new/2021/07/aws-appsync-supports-custom-authorization-with-aws-lambda-graphsql-apis/) authorization mode via CDK. We will integrate this endpoint with a very simple React web-app.

![](https://cdn-images-1.medium.com/max/2000/1*X8wJfgMbeIaItSJM_uMzhg.png)

## Fun fact

The first version of this article was based on independently provision the needed AWS resources via CDK, on its own folder/project. Nevertheless  in the [AWS Community Builders](https://aws.amazon.com/developer/community/community-builders/) Slack channel, I came to know that [a related feature](https://docs.amplify.aws/cli/custom/cdk/#reference-amplify-environment-name) was being released by the AWS Amplify team which brought me to revisit the article with slightly different but cleaner implementation. This synthetizes the awesomeness of the program. You can find the [before](https://github.com/aladevlearning/appsync-lambda-authorizers/tree/before-custom-resources) and [after](https://github.com/aladevlearning/appsync-lambda-authorizers/tree/after-custom-resources) custom resources implementation in GitHub.

## Add Custom resources

With latest Amplify now you can [add custom resources](https://docs.amplify.aws/cli/custom/cdk) by defining CDK stacks. A typical approach before this was to separate your CDK into a *cdk* or *infra* folder within your project. Now you can have it within the Amplify backend. Issues the below commands:

    npm i -g @aws-amplify/cli
    amplify add custom

Currently you can define custom resources by either *CDK* or *CloudFormation* templates, we will opt for the first choice and provide a name for the custom Resource e.g. *lambdaAuthorizerCustomResource*. This generates a skeleton CDK stack under the *amplify/backend/custom/<custom-resource-name>* path.

![](https://cdn-images-1.medium.com/max/2000/1*WM50WFpUMqOsI11bYsVs6Q.png)

Before we modify the pre-generated *cdk-stack.ts file* and create a *cdk.ts*, let’s look at the content of the CDK stack in the next section.

## Provision GraphQL via CDK

Being a huge fan of [Infrastructure as Code](https://docs.aws.amazon.com/whitepapers/latest/introduction-devops-aws/infrastructure-as-code.html) principle, I decided to create the GraphQL endpoint by using AWS CDK for Typescript language. Essentially, CDK abstracts CloudFormation stacks in a programmatic way. Below stack will provision:

* an AppSync GraphQL endpoint based on a [schema.graphql](https://github.com/aladevlearning/appsync-lambda-authorizers/blob/main/cdk/graphql/schema.graphql) defining the model and a Lambda authorizer configuration.

* An *Authorizer* Lambda function with its necessary IAM policies.

* A business-related *Payments* Lambda function containing CRUD operation on as on a defined model (here the *Payment* model) via its [GraphQL resolvers](https://graphql.org/learn/execution/). This Lambda is attached as a [datasource to AppSync](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-datasource.html).

* A DynamoDB table to persist the models.

Full code, outputting the GraphQL endpoint, can be found [here](https://github.com/aladevlearning/appsync-lambda-authorizers/blob/after-custom-resources/authorizer-app/client/amplify/backend/custom/lambdaAuthorizerCustomResource/cdk-stack.ts).
{% gist https://gist.github.com/aladevlearning/c91a3c42ae9864ac4250629ec935fdf0.js %}
It is important to note that now you can use Amplify project metadata such as ***project*** and ***environment*** name  to define your resources at run-time.

At the time of the writing I had to create a *cdk.ts* file in order to initialize the stack and associate it with the app:
{% gist https://gist.github.com/aladevlearning/339a96677cb874e373003b1fcdfd48ba.js %}
Finally, let’s build and deploy the changes:

    amplify build
    cdk deploy --app "npx ts-node cdk.ts" --parameters env=dev

Above steps could be manually performed AWS Console, but just with more steps and error-prone risk. Here below we show the visual output of the CDK:

![](https://cdn-images-1.medium.com/max/2000/1*SbWdB8ooe3YRocDetuPbcw.gif)

## Lens on Lambdas

We have provisioned two Lambda functions: one  “*glueing*” AppSync with DynamoDB as *datasource* and one performing authorization checks. **IMPORTANT:** Notice they have been prefixed with the data coming from our CDK stack: **authorizerappdev.**

### Datasource Lambda

The *Datasource* Lambda leverages AWS SDK to perform CRUD actions on DynamoDB table. Below snippet showcases listing of payments, the rest can be looked at [Github repo](https://github.com/aladevlearning/appsync-lambda-authorizers/tree/main/cdk/resources/payments).
{% gist https://gist.github.com/aladevlearning/93874a0f0c7c3ea5259106f5aa7b1561.js %}
### Authorizer Lambda

AppSync forwards any client requests to this function, by providing an authentication token. For this PoC, I leverage an RSA key pair to verify the payload of an incoming JWT token and its signing via a public key previously generated. This is done by using the [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) package.
{% gist https://gist.github.com/aladevlearning/484a0e77d56516a602ea47a11862773a.js %}
At this stage we just need a client consuming the GraphQL endpoint, so let’s look at it in details in the next section.

## Integration with Amplify

At the time of the writing (November 2021), the new Lambda authorizer is not yet available via Amplify CLI. This entails that we need to setup a manual integration with AppSync, which though is very simple.

Assuming you have [*configured* and *initiated* Amplify](https://docs.amplify.aws/cli/start/install/) in your project, All you need to do is to manually add this snippet as part of the Amplify *configure* method, usually located in your App.js/ts file — if using React.
{% gist https://gist.github.com/aladevlearning/f22a6b0ce6d43de8e39ce4a2e81ec206.js %}
To demonstrate the JWT verification, I have created a very dumb [React UI](https://github.com/aladevlearning/appsync-lambda-authorizers/blob/main/authorizer-app/client/src/App.js).

![](https://cdn-images-1.medium.com/max/2000/1*Qm1WWMtV3ShqYazZV8LgvQ.gif)

A JWT token gets generated by calling a local [Fastify](https://www.fastify.io/)NodeJs server exposing a *generate-token* endpoint. Details can be found [here](https://github.com/aladevlearning/appsync-lambda-authorizers/blob/after-custom-resources/authorizer-app/backend/server.js). The endpoint uses a private key in order to sign the generated JWT token, which then will be verified, as shown earlier, by the Lambda Authorizer function. In this case we just send a naïve foo/bar payload, but in real life must be much more complex and following [Oauth claims](https://tools.ietf.org/id/draft-spencer-oauth-claims-00.html) more strictly. The call is performed by calling the API endpoint and providing a GraphQL query and the JWT token.
{% gist https://gist.github.com/aladevlearning/6711206f9bf0ecb0ba469eeb5d1013a0.js %}
## Summary

Lambda authorizers and Custom Resources are yet another weapon to the Amplify and AppSync arsenal, opening for a myriad of use cases and combinations of single and multiple authorizers and third-party integrations. This article is intended as a starting point for customers to start using the Lambda Authorizer feature and just showed a very simple implementation which can then be extended for more further refinement.

## References
[**AWS AppSync now supports custom authorization with AWS Lambda for GraphQL APIs**](https://aws.amazon.com/about-aws/whats-new/2021/07/aws-appsync-supports-custom-authorization-with-aws-lambda-graphsql-apis/)
[**Building Scalable GraphQL APIs on AWS with CDK, TypeScript, AWS AppSync, Amazon DynamoDB, and AWS…**](https://aws.amazon.com/blogs/mobile/building-scalable-graphql-apis-on-aws-with-cdk-and-aws-appsync/)