What you'll learn
- prevent unauthorized users from performing sensitive GraphQL API queries and mutations
Learn more about the Webiny Security Framework in the Security Framework key topics section.
The code that we will cover in this tutorial can also be found in our GitHub examples repository.
At the moment, the
carManufacturers queries and mutations, that we added to our main GraphQL API in the API Package tutorial, are publicly exposed.
For example, if were to perform a simple
listCarManufacturers GraphQL query, we would receive a list of all car manufacturers:
Even more important, anybody can create new car manufacturers, with the
createCarManufacturer GraphQL mutation:
In most cases, this is not the desirable behaviour, and you'll certainly want to have control over who can perform these GraphQL operations, and who cannot.
In order to secure our GraphQL API, we have to revisit the GraphQL resolver functions that were generated for us via the GraphQL API package scaffold.
Learn more about GraphQL resolver functions in the official GraphQL documentation article.
All of the GraphQL resolver functions are located in the
For purposes of this tutorial, we can open the simplest resolver, which is the
getCarManufacturer.ts, and add the following lines of code:
If you're curious about the
CarManufacturersPermission type, check its definition in packages/car-manufacturers/api/src/types.ts:173.
In order to actually compile the code changes we're about to make and see them in our GraphQL API, we need to run the following Webiny CLI command:
To learn more, check out the Use the Watch Command guide.
Now, to see this new piece of authorization logic in action, we can use a GraphQL client, for example the GraphQL Playground, point it to our GraphQL API's URL, and try executing the following query:
Misplaced GraphQL API URL?
yarn webiny info command in your Webiny project folder will give you all of the relevant project URLs, including the URL of your GraphQL API.
Without including the appropriate
Authorization request header, we should receive the following error response:
If you received the
SECURITY_NOT_AUTHORIZED error, that means authorization was successful.
On the other hand, if a valid
Authorization request header is included, or in other words, the current identity actually has access to the Car Manufacturers module, the data should correctly be returned.
To manually test that, we can simply create a new user via the Webiny Security application, and either place it into the default Full Access security group, or even better, into the newly created Car Manufacturers security group. Which is what the following screenshot is showing:
Once we've created the user, we can log in into the Webiny Admin Area with it (using its username and password), and execute the same GraphQL query, this time using the built-in API Playground. We will use this client simply because of the fact that, upon issuing GraphQL operations, it will automatically attach the correct
Authorization request header for us. In other words, it will perform GraphQL operations as the currently logged in user.
Learn more about the API Playground GraphQL client in the API Playground guide.
So, as we can see in the following screenshot, the GraphQL query was successful, as we've successfully received the car manufacturer data in the response:
This means that the user we're currently logged in with has the appropriate security permissions, and that the newly added authorization code works as expected.
Before we wrap this up, note that this is just a single resolver we secured, and that you should implement the same logic into others as well.
Finally, in case you start seeing yourself copying some of the authorization related code, it's certainly recommended that you extract it into one or more separate utility functions. This way we're not repeating our selves (DRY) and our code will be more maintainable and less error-prone.
If you're not building a multi-locale module, feel free to skip the
await context.i18nContent.hasI18NContentPermission(); checks in your GraphQL resolvers and simply start with your own authorization checks.
But of course, be aware that if your project ends up being multi-locale, then users will be able to execute your GraphQL resolvers in every created locale (unless they are prevented by your custom authorization logic).