Secure your GraphQL API within a Spring-Boot App
Tags: graphql, java, springboot, api
Published: 2020-06-13 16:56:57

This is the third episode of the series [GraphQL, from Theory to Real-World with Spring boot](https://medium.com/@philippechampion58/grapql-from-theory-to-real-world-with-spring-boot-d6b46a28027b?source=friends_link&sk=265f0f4063dbea9780de4a55e8370b14). The episodes are designed to be consumed independently, so feel free to start from what interest ou the most.

# Overview

In the [previous article](https://medium.com/@philippechampion58/understanding-graphql-error-handling-mechanisms-in-spring-boot-604301c9bedb?source=friends_link&sk=1d97101ee639e362b86fad68c2cc2a14), we’ve exposed a set of resources via a GraphQL API. Now we want to secure them to prevent unauthenticated and unauthorized access.

#### TL;DR

Check the corresponding video.

{% youtube 1PKqY50IjBw %}

> NOTE: Reading the previous article IS NOT mandatory, they are designed to be consumed independently by just checking out the [codebase on GitHub.](https://github.com/zero-filtre/springboot-graphql-error-handling)

Spring security offers us the `WebSecurityConfigurerAdapter::configure` method to configure our app security. It gives us a way to define the access level of some resources based on URLs. Unfortunately, this is not a mechanism that fits well with the GraphQL protocol as it does with REST APIs.

Actually, graphQL is using only one endpoint, usually `/graphql.` Hence we cannot secure our resources based on URLs. As we want some resources to be either accessed only by administrators, or by authenticated users or even opened to the public.

But it becomes possible if we use annotations on resolvers methods, coupled with Aspect-Oriented Programming (AOP), and that’s what we are going to do.

So, at the end of this article, you will know how to:

- Set up an aspect with Spring AOP,

- Use aspect-oriented programming coupled with custom annotations to secure your resources,

- Write tests to check your GraphQL API

---

# Project Setup

Clone the [code base](https://github.com/zero-filtre/springboot-graphql-error-handling) that we had in the [previous article](https://medium.com/@philippechampion58/understanding-graphql-error-handling-mechanisms-in-spring-boot-604301c9bedb?source=friends_link&sk=1d97101ee639e362b86fad68c2cc2a14):

```shell
git clone -n https://github.com/zero-filtre/springboot-graphql-error-handling.git && cd springboot-graphql-error-handling/

git checkout bd7a0b5c039c610de9c8355be0d1c5f5e5484655

git switch -c my_experimental_branch
```

We will make the resources:
**`createUser(username:string, password:string)`** public,

**`getUser(username:string, password:string)`** available for authenticated users only, and we will create an additional resource:

**`deleteUser(username:string)`**, to be available for admin users only.

Add the following dependencies to the `pom.xml`

```xml
...
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-test</artifactId>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <scope>test</scope>
</dependency>
...
```

Then we add the additional `deleteUser` resource which matches the following resolver method in `UserMutation.java`:

```java
public User deleteUser(String username) {
   return userService.deleteUser(username);
}
```

Don’t forget to define the `UserService::delete` method, which just removes the user corresponding to that username from the in-memory `List<User> users` and returns information about the deleted user.

Add **deleteUser** resource spec to the schema definition file: `src/main/resources/UserQL.graphqls` :

```graphql
type Mutation {
    ...
    deleteUser(username: String!): User
}
```

# Securing the resources

The strategy consists of:

- Authorizing all requests related to GraphQL: `/graphql`

- Then, thanks to **custom annotations**, specify, at the method level in resolvers, which methods are public, which ones **should be accessed only by authenticated users**, and which ones **should only be accessed by users with specific roles such as ADMIN.**

- Whilst with aspects, we will check if our annotations are applied or not and throw exceptions accordingly.

Let’s create the security configuration file: `SecurityConfig.java`

{% gist https://gist.github.com/imphilippesimo/90c336d9ca61119fc7ea486ebf15ac82 %}

This config tells our app to authorize all requests related to GraphQL so that we can check them at the resolver level with annotations.

We will have two annotations:
`@AdminSecured` appended to admin resources, and
`@Unsecured` appended to public resources.
All other endpoints will, by default, need authenticated users access.
It’s always better to forget to make a resource unsecured than to forget to secure it 😁

AdminSecured.java

```java
*/**
 * This annotation will trigger Admin security check for
 * the GraphQL resolver method where it is marked.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AdminSecured {}
```

Unsecured.java

```java
*/**
 * This annotation will disable security check for
 * the GraphQL resolver method where it is marked.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Unsecured {}
```

Now go on and annotate the resolver methods accordingly:

```java
@Unsecured
public User createUser(String username, String password) {
    return userService.createUser(username, password);
}

@AdminSecured
public User deleteUser(String username) {
    return userService.deleteUser(username);
}
```

`UserQuery::getUser` will be set as secured by default.

Let’s define the aspect that will scan these annotations.
First, we need to Enable AOP in the main application class, 
by adding `@EnableAspectJAutoProxy` annotation like so:

```java
@SpringBootApplication
@EnableAspectJAutoProxy
public class SampleGraphqlErrorHandlingApplication {
    public static void main(String[] args) {        SpringApplication.run(SampleGraphqlErrorHandlingApplication.class, args);
    }
}
```

Then the aspect class… But wait! ☝, What’s an aspect? 🤔

Aspects are related to Aspect-Oriented Programming (AOP) which gives you a way to encapsulate or modularize a behavior that is transversal and repeated across several types of objects and that is, normally, not easy to encapsulate in its own module.

Usually, those behaviors (logging, caching, transaction management…) are not related to business logic and they are so-called aspects.

> An aspect is a common feature that’s typically scattered across methods, classes, object hierarchies, or even entire object models [3] .

Example:
AOP provides you with programmatic control to specify that you want calls:

- To all methods annotated `@Timed` to trigger a timer before executing the actual body of that code,

- To all methods classes in the package `xxx.bank.account` to trigger a specific additional security check,

- etc

Without repeating yourself 😎

We are going to do something similar with our Aspect.

Yes, you have guessed it right, our aspect is about security check based on annotations.

`SecurityGraphQLAspect.java`

{% gist https://gist.github.com/imphilippesimo/2afcb6dabbb268635e0b581430510724 %}

Don’t worry, It seems complicated but it’s actually pretty simple.
Let’s go through each part of it to understand what it’s being done here.

First, As we defined this spring component as `@Aspect`, it becomes an interceptor and we want it to be the first to be triggered, before any other interceptor, since it is our security guarantor. That’s why we use `@Order(1)`

The first method `doSecurityCheck`is annotated with `@Before`which is an **_Advice_**, which means, according to AOP terminology: **action taken by the aspect at a specific point during the execution of the program**.

The `@Before` advice lets the action being executed before the specified **_PointCut_**s, which helps to **categorize elements of the program that the aspect will watch.**

`doSecurityCheck`is executed before **all GraphQL resolvers methods** that **are defined within our project** and that **are not annotated as unsecured**. These categories are then defined with the help of `@PointCut`.

`doSecurityCheck`checks the Spring security context to make sure the user is authenticated.

Similarly: `doAdminSecurityCheck` is executed before **all methods annotated as AdminSecured. **

`doAdminSecurityCheck`checks the Spring security context to make sure the user has the ADMIN role.

This is the code for the referenced `UnauthenticatedAccessException.java`:

```java
public class UnauthenticatedAccessException extends RuntimeException implements GraphQLError {

    public UnauthenticatedAccessException(String msg) {
        super(msg);
    }

    @Override
    public List<SourceLocation> getLocations() { return null; }

    @Override
    public ErrorClassification getErrorType() { return null; }
}
```

That’s it! 🏁

Now let’s start the app, launch [http://locahost:8080/graphiql](http://locahost:8080/graphiql) and:

- Create a user:

![](https://cdn-images-1.medium.com/max/2036/0*3sqVJxBQ5gkQZuC_)

Everything works as expected ✌🏾.

- Delete that user:

![](https://cdn-images-1.medium.com/max/2680/0*JcKCaksW7DDtEmCg)

We do not have the right to do that as expected ✌🏾.

- Get users:

![](https://cdn-images-1.medium.com/max/2542/0*h7ylf95s0nZj5QEU)

We need to log in first as expected ✌🏾.

Let’s test the remaining cases programmatically so that you can automate it in a pipeline and earn some time.

GraphQLSecurityTests.java

{% gist https://gist.github.com/imphilippesimo/720baf01b793a2bcdabc7f17c18857db %}

Notice that we restart the context after each test method with `@DirtiesContext` to make sure every method runs in a clean, not polluted context. But you should not abuse this, as it increases considerably your tests execution time.
Run the test and should have a 100% success.

Now our endpoints are secured 😎.

---

# Conclusion

GraphQL APIs are great but are different in so many ways from REST APIs, and the way to handle the security is no exception.

That’s why in this article, we saw how to use aspect-oriented programming coupled with custom annotations to secure our resources. Additionally, we also wrote tests to check the whole stuff.

I hope you enjoyed it. 

In the [next article](https://medium.com/@philippechampion58/testing-your-graphql-apis-in-a-spring-boot-app-9fe02ebccc35?source=friends_link&sk=c91ff02c10402469f6e9c3824a7d89cd), we will describe a strategy and apply a strategy to write fast, bulletproof tests for your GraphQL APIs with Spring boot.

Don’t forget, Feedback is a gift 🎁!

---

_References:_

[1][https://docs.spring.io/spring/docs/2.0.x/reference/aop.html](https://docs.spring.io/spring/docs/2.0.x/reference/aop.html)

[2][https://mi3o.com/spring-graphql-security/](https://mi3o.com/spring-graphql-security/)

[3][https://docs.jboss.org/aop/1.0/aspect-framework/userguide/en/html/what.html](https://docs.jboss.org/aop/1.0/aspect-framework/userguide/en/html/what.html)