Hi, everyone,
I would like to share an idea/prototype for implementing an access control layer with minimal effort. As the title suggests, I will be using the AWS Cognito service and a GraphQL directive. AWS Cognito provides excellent functionality for controlling access to REST APIs. However, it doesn't fully meet our needs because, with GraphQL, there is typically only a single POST endpoint that handles numerous queries and mutations.
Before we begin, I want to clarify that this is not a step-by-step guide on how to use AWS Cognito or an introduction to GraphQL, including how to create a GraphQL server or a lambda function from scratch.
Requirements
Let’s imagine we have a front-end application and an Article GraphQL service. This service provides simple CRUD mutations, such as publish
, delete
, and saveDraft
. Our task is to implement, with minimal effort, a way to manage access for our Cognito users to these endpoints. For example:
- The first user can only save draft.
- The second user can save draft and publish.
- The third user has full access, including delete operations.
Implementation
Cognito
As mentioned earlier, I will not cover how to set up the AWS Cognito service (user pools and users) in this article. I assume you already have it configured. However, I want to highlight that Cognito users support custom attributes. For more details, you can refer to this link. Before creating our first custom attribute, we will develop our own language. This technique is known as a DSL.
A DSL (Domain-Specific Language) is a programming or scripting language designed to solve problems within a specific domain. Unlike general-purpose programming languages (such as Python, Java, or TypeScript), which are built to handle a wide range of applications, DSLs are tailored for specialized tasks.
First and foremost let's come up with a syntax.
-
*
- means allow all actions -
|
- the separator between the namespaces -
/
- the separator between a namespace and an action(s)
Let’s agree on the following rules:
-
article/*
- allows all actions. -
article/saveDraft
- allows only the saveDraft action. -
article/saveDraft,publish
- allows both the publish and saveDraft actions. -
article/*|user/*
- allows everything for the article and user namespaces.
As you can see, creating your own DSL is straightforward, and this technique is widely used in various areas, such as SQL, configuration files, and Infrastructure as Code.
Now, let’s create a custom attribute that will include a list of actions we want to allow or deny.
Create custom attribute action
.
The next step is to create the users with the action custom field.
Code
That’s pretty much it for the AWS Console setup; now we can dive into the code. You can easily find the complete code on GitHub. Here, I’ll focus on the most essential parts.
You can find a tutorial on creating and setting up an Apollo Lambda handler here. The key difference in my approach is that I parse the JWT token from the event and set the custom:action
property in the context. As a result, the context includes the action
property containing all the rules we added in AWS Cognito.
The next step is to parse the action
property from the context and determine whether to allow or deny the action. For this task, we’ll use a GraphQL directive. You can find a guide on how to build it from scratch by following this link. Here, I’ll provide the code and an explanation of how to check access using it.
The logic of the directive is straightforward and involves three steps:
Locate the Namespace: Split the entire string using the namespace separator (we agreed earlier that it is |) and find the specific namespace by name.
Separate Namespace and Actions: Use the / separator to split the namespace from the actions.
Check Actions: Map all actions and verify whether the action is allowed or denied.
The final piece of our setup is the GraphQL schema.
As you can see, simply add the directive in front of the mutation and provide the namespace name as an argument.
That’s pretty much it! This approach seems not only useful and easy to implement but also flexible, cost-effective, and one of the fastest ways to add an Access Control Layer to your application.
To try it out:
Fork the repository and deploy it using your own AWS account. All resources are defined using AWS CDK. You can find instructions on how to bootstrap and deploy an AWS stack in this guide.
I’ve created a public Postman collection for your convenience. Please follow the guide provided within the collection.
If you’d like to support my work, you can subscribe, give me kudos, buy me a Ko-Fi, or share your valuable feedback. Your support and insights mean a lot!
Top comments (0)