No Tresspassing: Introduction to GraphQL Authorization

Authentication and authorization are very complex topics for any public-facing application. Unless you want to make every piece of data and every possible action public (does something like this even exist?!), you’re forced to implement both processes mentioned earlier into your software. However, using Dgraph, we can vastly simplify these complex topics and implement them in about 20 minutes.

This tutorial assumes that you understand the basics of GraphQL schema. If you don’t, please read The 10 Minute Introduction to GraphQL Schema.

Authentication vs. Authorization

Before continuing, let’s understand the difference between authentication and authorization.

Authentication: The authentication service or layer identifies users based on the credentials they provide. If the credentials are valid, the user is authenticated.

Authorization: The authorization layer checks if the authenticated users can access the resources or perform the actions they are trying to access/perform.

General Authentication + Authorization Flow

First, let’s cover the basics of the auth+auth flow using Dgraph. GraphQL Auth Flow

As you can see in the image above, the frontend acts as the middleman between the authentication service and Dgraph (which includes the authorization layer).

The magic starts with the frontend. The frontend asks users to authenticate with the authentication service (either a service like Auth0 or a custom service). The authentication service returns a JWT with claims to allow our authorization service to understand who is requesting access. The frontend includes this JWT with every request. Once Dgraph gets a request, it validates the JWT. It then opens up the custom claims and injects the values into the authorization rules defined in our schema. Finally, Dgraph returns the appropriate data based on whether the authorization rules pass or fail.

Adding Authorization to your Schema Adding authorization to your schema is done with two parts:

Enabling Authorization The first step to adding authorization is to enable authorization using the Dgraph.Authorization comment. Add this comment to the end of your schema.

# Dgraph.Authorization {"VerificationKey":"","Header":"","Namespace":"","Algo":"","Audience":[]}

Note: The space between # and Dgraph.Authorization is essential.

Let’s understand what each of the arguments above means:

  • VerificationKey: This is the public key (Can also be the secret key). Used to verify your JWT
  • Header: The header that includes the JWT in each request.
  • Namespace: The namespace is the field in the JWT that includes our custom claims.
  • Algo: The algorithm that your key is using.
  • Audience: A list of valid audiences. Used to validate the JWT.

The @auth Directive

We’ve enabled authorization, and now we need to create authorization rules using the @auth directive.

Let’s use the example of a todo app. We’ll start with the schema below:

type Todo {
  id: ID!
  value: String! @search(by: [fulltext])
  completed: Boolean! @search
  user: User
}

type User {
  username: String! @id @search(by: [hash])
  name: String @search(by: [exact])
  todos: [Todo] @hasInverse(field: user)
}

We want to lock down the Todo type, and only allow users to see Todos that they’ve created.

What we’ll do is add a rule that pulls a field from the JWT claims. USER is the field we will use, and it will contain the user’s username. Then, we’ll create a query that uses this field to pull Todos that are created by a User with a username equal to our USER field.

type Todo @auth(
  query: { rule: """
    query($USER: String!) {
      queryTodo {
        user(filter: { username: { eq: $USER } }) {
          __typename
        }
      }
    }"""}), {
  id: ID!
  value: String! @search(by: [fulltext])
  completed: Boolean! @search
  user: User!
}

type User {
  username: String! @id @search(by: [hash])
  name: String @search(by: [exact])
  todos: [Todo] @hasInverse(field: user)
}

As you can see, we added a query rule. There are four types of rules: query, add, update and delete. Each one corresponds to a different kind of action. Our query rule locks down any form of query on the Todo type.

As you can see, it’s effortless to add authorization to our schema. If you want to see a practical implementation of Dgraph authorization using Auth0, take a look at A Match Made In Heaven: Authentication and Authorization with Dgraph and Auth0.

To read more about authorization, take a look at the authorization documentation.