All Articles

Easy authentication in GraphQL with Express and Apollo

When starting with GraphQL you need to familiarize yourself with a lot of new concepts: like schema’s and resolvers. In this tutorial I will show how easy authentication can be if you harness the power of GraphQL and Express. Combined you have best of both worlds: querying data like a champ and using traditional API calls for mundane stuff like user creation and authentication.

Getting started: boilerplate app

If you want to code along, you can check out this repo and clone the start of the tutorial release with this command:

git clone git@github.com:DirkWolthuis/graphql-express-auth-tutorial.git --branch v1.0

In this project I have setup webpack to compile the app.js file inside the dist directory. It serves a basic Express + GraphQL app. After cloning the project you need to run npm install to install the dependencies. Finished installing? You can run npm start to start the app. It will server a GraphQL endpoint on http://localhost:3000/graphql. Feel free to try it out: you can query users, user, todos, todo. The goal of this tutorial is to protect the GraphQL endpoint with JSON Web Token authentication, in other words: if a user is not authenticated he or she can’t access the data from the GraphQL endpoint.

GraphQL data

Step 1: creating a authentication endpoint

In this step you are going to create a Express endpoint to authenticate and retrieve a JWT (token). To test this you need a tool like Postman (it’s free), to test your endpoint. First we will create a new post endpoint, just above where we start the app.

/*
    Express routes/endpoints
*/

app.post('/get-token', (req, res) => {})

/*
    Starting the app
*/
app.listen(port, () =>
    console.log(
        `🔥🔥🔥 GraphQL + Express auth tutorial listening on port ${port}!`
    )
)

I use the /get-token route for my endpoint, but you are free to use whatever name you like. In this function we need to three things:

  1. Check if the user that is trying to authenticate exists
  2. Check if the password matches the password in the database (or in our case, the mock.js file
  3. Create and return the token
    /_
    Express routes/endpoints
    _/

    app.post('/get-token', async (req, res) => {
    const { email, password } = req.body
    const user = users.find(user => user.email === email)
    if (user) {
    //we use bcrypt to compare the hash in the database (mock.js) to the password the user provides
        const match = await bcrypt.compare(password, user.password)
        if (match) {
            //we create the JWT for the user with our secret
            //inside the token we encrypt some user data
            //then we send the token to the user
            const token = jwt.sign({ email: user.email, id: user.id }, SECRET_KEY)
            res.send({
                success: true,
                token: token,
            })
        } else {
            //return error to user to let them know the password is incorrect
            res.status(401).send({
                success: false,
                message: 'Incorrect credentials',
            })
        }
    } else {
        //return error to user to let them know the account there are using does not exists
        res.status(404).send({
            success: false,
            message: `Could not find account: ${email}`,
        })
    }
    })

A simple function that checks the user and the password and returns errors with messages if the user makes a faulty request. Time to test our endpoint! Let’s fire up Postman. Create a new post request on to your chosen route. For me it’s localhost:3000/get-token. Choose body and select the raw, with the setting on JSON. Now add a JSON object with the following:

{
    "email": "hallo+spam@ikbendirk.nl",
    "password": "Test123!"
}

Send the request and bam! We get our token.

Testing endpoint with Postman

Step 2: protecting the GraphQL endpoint

In the next step we’ll make sure only authenticated user (users with a valid token) can access data via the GraphQL endpoint. To create this feature will use Apollo context. Apollo context let’s you put information into a context object that is accessible by the resolvers. And it’s created on each request, with makes it easy to use for authentication. First let’s setup our context function.

/*
        Creating our Apollo context function
    */

const context = ({ req }) => {}

/*
        Creating the Apollo server
    */

const server = new ApolloServer({ typeDefs, resolvers, context })

We added our context to the Apollo server. Now we need to do three thing:

  1. Get the token from the request
  2. Check if the token is valid
  3. Throw an error if it’s invalid
const context = ({ req }) => {
    // get the user token from the headers
    const token = req.headers.authorization || ''
    const splitToken = token.split(' ')[1]
    try {
        jwt.verify(splitToken, SECRET_KEY)
    } catch (e) {
        throw new AuthenticationError(
            'Authentication token is invalid, please log in'
        )
    }
}

The the code above we get the token from the headers, verify it and return a error if it’s not valid. The AuthenticationError is a specific Apollo error to signal that Authentication has failed: therefore you need to import it from the apollo-server-express package.

const {
    ApolloServer,
    gql,
    AuthenticationError,
} = require('apollo-server-express')

Let’s check if our solution worked. Go to the GraphQL endpoint http://localhost:3000/graphql and check if you can still access your data. Great our app throws an error when you try to access it without a token.

Authentication error GraphQL

Now for the final piece: let’s try to add the token we retrieved earlier. On the GraphQL endpoint you have a tab called HTTP HEADERS . Let’s add our token there:

{
    "Authorization": "Bearer YOUR_TOKEN_HERE"
}

Authentication success GraphQL

And there you go: authentication with GraphQL, Apollo and Express.

Want the code? Checkout Github.