Authentication and Express Middleware with GraphQL

John Au-Yeung - Jan 25 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

We can create a simple GraphQL server with Express. To do this, we need the express-graphql and graphql packages.

In this article, we’ll look at how to use middleware with Express GraphQL.

Express Middleware

We can use Express middlewares as usual if we use express-graphql to build our GraphQL server with Express.

The request object is available as the second argument in any resolver.

For example, if we want to get the hostname of a request in our resolver, we can write:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');

const schema = buildSchema(`
  type Query {
    hostname: String
  }
`);

const loggingMiddleware = (req, res, next) => {
  console.log(req.hostname);
  next();
}

const root = {
  hostname(args, request) {
    return request.hostname;
  }
};

const app = express();
app.use(loggingMiddleware);
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(3000, () => console.log('server started'));
Enter fullscreen mode Exit fullscreen mode

In the code above, we created our schema as usual to get the hostname of the app.

Then we added our loggingMiddleware to log the hostname. It calls next so we can use our graphqlHTTP middleware.

Then in our root resolver, we added a hostname method, which takes the request parameter as the second argument, which has the Express request object.

This is where we can return the hostname property from request so that we can return it in the response.

This means that we can continue to use middleware to handle authentication as we did with REST APIs.

Popular authentication options for Express include Passport, express-jwt , and express-session .

Authentication

We can use jsonwebtoken in our Express GraphQL server as follows to add authentication via JSON web token.

To do this, we first install jsonwebtoken by running:

npm i `jsonwebtoken`
Enter fullscreen mode Exit fullscreen mode

Then we can include it in our app and then add it to our Express GraphQL server as follows:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
const jwt = require('jsonwebtoken');
const unless = require('express-unless');

const schema = buildSchema(`
  type Query {
    hostname: String
  }
`);

const root = {
  hostname(args, request) {
    return request.hostname;
  }
};

const verifyToken = (req, res, next) => {
  jwt.verify(req.headers.authorization, 'secret', (err, decoded) => {
    if (err){
      return res.send(401);
    }
    next();
  });
}
verifyToken.unless = unless;

const app = express();
app.post('/auth', (req, res) => {
  const token = jwt.sign({ foo: 'bar' }, 'secret');
  res.send(token);
})

app.use(verifyToken.unless({ path: ['/auth'] }));
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(3000, () => console.log('server started'));
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the verifyToken middleware to verify the token that’s issued by our auth route.

In verifyToken , we called jwt.verify to verify the token that we passed into the Authorization header. If we get an error, then we send a 401 response.

Otherwise, we call next to proceed to the next middleware our route.

In the auth route, we issue our authentication token by calling jwt.sign with whatever content we want as the first argument and the token’s secret in the second argument.

Also, we excluded the verifyToken middleware from the auth route by using the express-unless middleware.

We did that by assigning unless to verifyToken.unless .

Then now when we want to make a request to our GraphQL server via the /graphql route, we have to pass in our auth token to the Authorization header.

This keeps our GraphQL requests more secure. However, we should have an encrypted secret if we’re going to JSON web tokens in the real world.

Conclusion

We can use Express middleware for logging, authentication, or whatever we need them for.

To include middleware, we just call the app.use method as usual.

We can exclude routes from using the middleware with the express-unless package.

To add authentication via JSON web tokens, we can use the jsonwebtoken package to add token issuing and verification capabilities to our Express GraphQL server.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .