JWT Authorization In A GraphQL API Using Golang

If you’ve been keeping up, you’ll remember I released a very popular tutorial titled, Getting Started with GraphQL Using Golang which was more or less a quick-start to using GraphQL in your web applications. Since then, I demonstrated an alternative way to work with related data in a tutorial titled, Maintain Data Relationships Through Resolvers with GraphQL in a Golang Application. Both articles are great, but they left out an important feature that most modern APIs must have. Most modern APIs must have a way to authorize particular users to access only certain pieces of data and not all data offered by the service.

One of the most popular ways to enforce some kind of authorization in an application is through the use of JSON web tokens (JWT). Users authenticate with a service and the service responds with a JWT to be used in every future request so that way the password is kept safe. The service can then validate the JWT to make sure it is correct and not expired.

We’re going to see how to protect particular GraphQL properties as well as entire queries using JSON web tokens and the Go programming language.

I’ve been creating RESTful APIs much longer than I’ve been creating GraphQL APIs. A while back I wrote about using JWT in a RESTful API created with Golang and while different, much of the logic will be carried over into this tutorial.

Creating a GraphQL Application with the Project Dependencies

Before we start adding code to the project, let’s create the project and download any project dependencies that will be used. Somewhere within your $GOPATH, create a project directory and a main.go file. We’re going to store all of our project code within this main.go file.

With the project created, execute the following from the command line:

go get github.com/dgrijalva/jwt-go
go get github.com/graphql-go/graphql
go get github.com/mitchellh/mapstructure

The mapstructure package will allow us to easily convert map variables into native Go data structures. While not absolutely necessary, the mapstructure package will make our lives a little easier. The graphql package will allow us to create GraphQL objects and process queries while the jwt-go package will allow us to sign and validate JSON web tokens.

Generating and Validating JSON Web Tokens (JWT) with Golang

Now that we have our project created and the appropriate dependencies in hand, let’s start adding some code. We’re going to start by adding our boilerplate code and the logic for creating and validating JSON web tokens.

This particular example will use accounts and blogs. Each account can have any number of blogs and each blog will be tied to account. However, we’re not going to be demonstrating a relationship. Instead, accounts will be protected via a JWT and only the Pageviews property of a blog will be protected by a JWT.

When signing and validating a JWT, we need to be using a secret:

var jwtSecret []byte = []byte("thepolyglotdeveloper")

In reality the value should not be hard coded into our application because it is considered sensitive like a password, but for this example it is fine.

We’re not using a database in this example so hard coding some mock data will work out fine. We just need a few accounts and a few blogs to get a good idea about what is happening.

Now for the part that truly matters for this particular example. We need a way to create and validate JWT data. Even though this is a GraphQL API, we’re still going to have a RESTful endpoint for signing users in and returning a JWT.

Remember, we don’t have a database for this example. What we’re doing is taking a username and password sent via the HTTP request and creating a JWT token from it. Then we sign this token using our secret and return the signed token back as a response. Had this been using a database, we probably would have added authentication logic for a particular user. If you really wanted to be production ready, you would not include the password in the token and you’d probably add an expiration time that you check when you validate. We’re not going to worry about any of this for our example.

The CreateTokenEndpoint is an endpoint function that will be accessible via an HTTP request. Our validation function will be a little different.

Our ValidateJWT function is not an endpoint function. Instead we’re going to call it as we need it. If no token is present, we’re going to respond with an error, otherwise we’re going to parse the token using our secret. If the token is valid we’re going to decode it and return the decoded value, otherwise we’re going to return an error.

There wasn’t much to the JWT signing and validation process. If we had a database things wouldn’t really be any more complex than what we saw. Most of our complexity resides in the GraphQL piece which comes next.

Developing the GraphQL Logic and Protecting Data with Authorization

We’ve got our JWT logic and we’ve got our mock data in place. Now we need to define our GraphQL objects, queries, and schema which power the actual API. Take a look at the following GraphQL objects for our mock data:

Nothing too complex right? We’ve essentially converted our native Go data structure to a GraphQL data structure of the same design. Aren’t we supposed to make our pageviews field protected? Yes we are, and it can be done like the following:

We’ve added a Resolve function for the particular property so we can define logic for the property. When the field is included in a query we call the ValidateJWT token using a value that we’ll eventually pass into our Context. If this token is present and valid, then return the value that already existed for this particular field, otherwise an error will be returned.

Before we get into the context side of things, let’s look at the possible queries.

The above says that we have an account query and a blogs query. In the account query we run our ValidateJWT function to check for a valid token. A valid token is required to run this query at all. If we have a valid token we check the token user against the mock data. We do this because we only want account data for the signed in user, not other users.

The blogs query is a bit different. We have no restrictions on the query itself, only if the user tries to query for the pageviews field.

Remember the context I mentioned earlier? We can define a value to pass other than the query itself using the Context property. In this case we’d be collecting a token from the query parameters. We could easily collect this token from the header information of the request as well.

Sample GraphQL Queries with cURL and the Command Line

You may or may not be confused by everything we just saw. Don’t worry it took me a while to figure things out as well. Now we want to test what we’ve done to validate that everything works as expected.

After running the application, execute the following in your Terminal:

Just make sure that the code ends up in a new project file within your $GOPATH path. It is by no means the only solution to the authorization problem or even the best solution, but it is one that I’ve found to be easy to implement and it works well.

Conclusion

You just saw how to authorize users to obtain certain data fields or execute certain queries with GraphQL using JSON web tokens (JWT) in the Go programming language. Using JWT with GraphQL is an alternative to the RESTful API approach that I had previously demonstrated.

If you’re just getting started with GraphQL, this JWT stuff might be over your head. Take a step back and check out my getting started guide and then circle back.

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.