DEV Community

AppSync Lambda authorizers via new Amplify Custom Resources

Amplify and 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 to add the new AWS Lambda authorization mode via CDK. We will integrate this endpoint with a very simple React web-app.

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 Slack channel, I came to know that a related feature 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 and after custom resources implementation in GitHub.

Add Custom resources

With latest Amplify now you can add custom resources 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
Enter fullscreen mode Exit fullscreen mode

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/ path.

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 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 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. This Lambda is attached as a datasource to AppSync.

  • A DynamoDB table to persist the models.

Full code, outputting the GraphQL endpoint, can be found here.



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:


Finally, let’s build and deploy the changes:
amplify build
cdk deploy --app "npx ts-node cdk.ts" --parameters env=dev
Enter fullscreen mode Exit fullscreen mode

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:

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.

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 package.


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 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.


To demonstrate the JWT verification, I have created a very dumb React UI.

A JWT token gets generated by calling a local FastifyNodeJs server exposing a generate-token endpoint. Details can be found here. 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 more strictly. The call is performed by calling the API endpoint and providing a GraphQL query and the JWT token.

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
Building Scalable GraphQL APIs on AWS with CDK, TypeScript, AWS AppSync, Amazon DynamoDB, and AWS…

Top comments (1)

Collapse
 
alexandroid profile image
alexandroid

It seems a bit weird to reference internal AppSync role when setting up permissions for it to invoke the authorizer Lambda (allowAppSyncPolicyStatement). I would suggest an alternative:

 authorizerLambda.addPermission('LetAppSyncInvokeMe', {
   action: 'lambda:InvokeFunction',
   principal: new iam.ServicePrincipal('appsync.amazonaws.com'),
 });
Enter fullscreen mode Exit fullscreen mode