Putting it All Together - Dgraph Authentication, Authorization, and Granular Access Control (PART 4) - Dgraph Blog

The last in a 4-part series by community author Anthony Master.

This is the last of a four part series:

  1. Building an Access Control Based Schema
  2. Authorizing Users with JWTs and Rules
  3. Authenticating Against a Dgraph Database and Generating JWTs
  4. Bringing Authentication into the GraphQL Endpoint as a Custom Mutation

Continuing in our series as the fourth and final part we will discuss how to bring authentication into our Dgraph GraphQL endpoint with a custom mutation. So far we should have the following:

  1. A schema set up with @auth directives.
  2. A user to authenticate with.
  3. A url link to your functioning authentication script.

PART 4 - Bringing Authentication into the GraphQL Endpoint as a Custom Mutation

What we need to add to get the final product:

  • A remote type in the schema to receive the response from the authentication script.
  • A custom mutation to point to the authentication script. Note: This could be done with a custom Query or Mutation, but I like to think of the authentication process of validating a user and creating a JWT as a mutation, because it is creating something that is not there, the JWT.

So back in your schema, let’s begin this with creating the type “AuthResponse” that will transport the responses from our script back to the user. Remembering back to our script we wrote in Part 3, we are returned an object with four properties: token, username, expires, and possibly admin. We can take these properties and create the type. By appending the @remote directive onto the type, Dgraph will not generate any queries or mutations for this type. This is what we are wanting since the data from this type is not actually being stored in the Dgraph database.

type AuthResponse @remote {
  token: String
  username: String
  expires: DateTime
  admin: String
}

This type is all good and dandy, but right now it does nothing. Literally nothing at all besides take up space in our schema. To use this type we will need to define our Mutation. Now this is a little tricky because normally Dgraph handles all the work (yes literally, all the work!) in building Queries and Mutations.

Normally by now anyone who has experience with GraphQL and may be new to Dgraph would be used to spending days/weeks/months writing resolvers that point to Queries and Mutations. This will bring back some of those memories, but this time we will do it with only 9 lines of code. We are going to write a Mutation in the schema that will auto generate a resolver based on the parameters that we give it in the schema.

Now to someone who may be newer to GraphQL, let me direct your attention to the fact that we are going to create a Mutation type in our Schema. This single Mutation type will hold all of the custom Mutations that we write. There can only be a single Mutation type and a single Query type.

We will create the Authenticate Mutation which requires a username and a pass, and then use the @custom directive to tell Dgraph how to resolve this Mutation. We will provide the url to our function we created before, pass the method as POST, pass the JSON body with the username and pass.

type Mutation {
  Authenticate(username: String!, pass: String!): AuthResponse @custom(http: {
    url: "https://yourdomain.com/functions/authenticate" # wherever you deployed your function to.
    method: "POST"
    body: "{ username: $username, pass: $pass }"
    secretHeaders: ["Content-type"]
  })
}

If you noticed in that Mutation @custom directive, we also passed a secretHeaders property. This is a lesser known property and late documented feature. But you can pass a header defined in the schema to this http request. We are passing the following “Content-type” header.

# Dgraph.Secret Content-type "application/json"

Save this schema and that concludes our lesson. Well I will give you the example of how to use it. To authenticate a user and generate a JWT, all you have to do now, is to use the following mutation:

mutation Login($username: String!, $pass: String!) {
  Authenticate(username: $username, pass: $pass){
    token
    username
    expires
    admin
  }
}

I hope that this series helps you understand how to Authenticate User, generate JWTs, and build a schema that can support group ACL.

Huge thanks from Dgraph to Anthony for coming forward to write some great blogs. If you are using Slash GraphQL or Dgraph and would like to write a community post, reach out to Michael, Zhenni or Apoorv in our discuss community

ReferencesTop image: Chandra X-ray: A Crab Nebula Walks Through Time
Anthony Master, Author

Anthony has been in the web development realm since 2007. Having a Bachelors of Theology in Missions, which is uncommon in this field, he has received no formal education for Computer Science. He has learned most things the hard way which sometimes has its benefits. Anthony’s passion has brought him to developing a web application serving Churches, Missionaries, and other ministries. Having arrived at a crossroads where relational databases were not able to handle their workflow, they decided to use Dgraph being an early adopter of the GraphQL endpoint and Slash.


This is a companion discussion topic for the original entry at https://dgraph.io/blog/post/putting-it-all-together-part4/

Holy. It makes my head explode. As I have written in Go for the function and can’t copy/paste your tutorial, no success since I started to follow. I should’ve used auth0 already :joy:

What part are you stuck at? The script to generate the JWT?

Processing JWT-related seems ok. I’m not exactly sure but parsing the response of the user info from Slash have been failed. Basically here is the code as a function which I have tested with Vercel.
https://gist.github.com/1l0/7e1e6e4eb7da887dfeb8d2afd80bd059
Sorry for the messy code, you can replace consts to yours.