Json web token to authenticate access to a GraphQL server

You may want to ensure that some users are properly logged in when accessing your GraphQL server. JsonWebToken can help with this.

GraphQL access protection

One of the easiest way to authenticate a user when accessing the GraphQL server is to use a JsonWebToken token and pass it to your GraphQL requests.

This token will be used by your backend to identify the user doing the request. You can also associate an expiration date to that token to automatically force a new login after a given amount of time.

Json Web token generation

There is a node module to generate the Json Web Token : node-jsonwebtoken.

You will need a secret to be used by this module.

You can create a constant.js file to store this secret:

export default {
  jwtSecret: '4A40333B-EC26-4E18-A976-9B030C23A484',
};

and you can have access to this secret using:

import {jwtSecret} from './constant';

You can generate the token when the user is logged in and associate a payload to this token.

import jwt from 'jsonwebtoken';

const token = jwt.sign({
  id: user.id,
  name: user.name,
  email: user.email
}, jwtSecret);

And then return this token in a GraphQL response:

{
  "data": {
    "login": {
      "email": "pcarion@hotmail.com",
      "isLoggedIn": true,
      "jwt": "eyJ0eXAiOiJKV1QCJiOiJIUz.../...8iCJ5LxooBz3Uh8MByBsdMI"
    }
  }
}

Once the client retrieves this payload, the token has to be persisted. The browser’s localstorage can be used for that:

localStorage.setItem('jwt_token', token);

The localstorage may not be the safest way to store your token. But that’s still the easiest way to start.

Inject token in HTTP requests

Once you have the token, you can use Relay.injectNetworkLayer to inject this value in the HTTP header.

var token = localStorage.getItem('jwt_token');

Relay.injectNetworkLayer(
  new Relay.DefaultNetworkLayer('http://localhost:8080/graphql', {
    headers: {
      Authorization: 'Bearer ' + token
    }
  })
);

Process JSon Web Token on the server side

On your backend, you may want to use the express-jwt middleware to process this token on each request:

import {jwtSecret} from './constant';
import jwt from 'express-jwt';

app.use(jwt({
  secret: jwtSecret,
  credentialsRequired: false,
  userProperty: 'user',
}));

The credentialsRequired is here set to false so that the request won’t fail if the token is not there: this may be useful if there are some requests which may not need to be protected.

If that’s the case it is up to the application layer to check the value of request.user to check if the user is logged in or not.