This post is a follow-up on a previous piece I wrote last week discussing how to add authentication to a GraphQL server using passport. I’m going to build off that post and discuss how to wrap generated OAuth tokens with a secure JSON Web Token (JWT) so that access tokens are not passed over the wire.

In the previous post, the app was using an OAuth strategy with the passport module to persist a user session on the node server. The key thing to know when using JSON Web Tokens is that there is no server session.

There is no server session

Essentially, we are going to encode a JWT on the server using a secret server key and send it back to the client as a cookie. After the response back to the client, the server doesn’t know anything about the JWT locally because it is not persisted. On every request from the client that needs to be authenticated, the client will send back that JWT using the cookie that it received. Then the server can read the incoming request, get the cookie’s JWT value, decode it using the secret key again, and if everything is good, do whatever it needs to with the decoded info and pass it to the protected route. This, in a nutshell, is how JWT works. It’s pretty straightforward once you wrap your head around a few of the key ideas. I’ll show you how I implemented it with graphql-yoga and the existing passport strategy I had in place to get the access token for the Spotify API.

First thing that is needed for this is the passport-jwt module that will be plugged into passport. This module will help us to define a middleware strategy for how to get the JWT from the cookie on the incoming request and inspect it to make sure it is valid. Next, we will need jsonwebtoken which will be the package used to generate the actual JWT.

Let’s take a look at the first snippet of code. This is the function that is going to generate the JWT. JWT’s are what they say they are — a token generated from JSON to be used on the web. Here I am passing in a user, but this could literally be any piece of JSON data that you’d like to be encoded. The important part here is really the secret key that is used to encode it. It’s going to use the same key to decode it when the token is sent back from the client.

Next, I am generating this token after I have received the authenticated user data from the Spotify OAuth login flow. My app opens a new modal window when logging the user into Spotify and then it re-directs back to route on my node server.

set-jwt-cookie

This code snippet is creating the JWT and also placing it as a cookie on the response that is set back. After this, the server forgets the JWT ever existed and the browser sets the cookie.

The final step is placing the JWT authentication in front of a route on the node server now that the JWT has been issued. For my use case, I am using graphql-yoga, luckily their server exposes the express application instance, so middleware can be placed on the /graphql route like so

graphql-yoga-middleware

An important thing to remember is using passport middleware on their server is that it needs to be initialized again! This tripped me up the first time I was trying it.

Finally, here is the strategy code that I am using for passport-jwt :

passport-jwt-strategy

Here I am passing in a custom extractor function that pulls the cookie off of the incoming request. The module then uses the secret key to decode the token. Once this is done, it can pass the unencoded data along to the next middleware ….

which in my case is the GraphQL server, where I intercept the request again and grab the fresh user data off the request and pass that down into the GraphQL context. This data has the access token that my API needs to make calls to the Spotify API to get data. With this in place, my /graphql endpoint is successfully setup behind authentication.

Here is the commit where I added JWT auth to my server.

Happy Hacking!

Header photo credit