GraphQL Authentication with React Native & Apollo [Part 1/2]

Using Express, MongoDB, and JSON Web Tokens

I’ve been playing with Apollo a lot lately and, as with nearly any app, I needed to add authentication to that app. I looked around but couldn’t find any posts specifically on the subject of authentication using React Native, GraphQL, and MongoDB — so that’s what we’ll be covering today.

In part one of this series you’ll learn how to configure the server (using GraphQL/Apollo, Mongo, Express, and JSON Web Tokens). In part two we’ll setup the React Native client to interact with it all.

The app we’ll be building is very simple, but will demonstrate the critical pieces of an authentication flow. It will have 3 screens:

  • Login
  • Register
  • Log out

Ready? Let’s go.

Prefer Video?

Prefer video tutorials? I made this tutorial into a video, which can be found below.

Setup

We’re going to use three tools throughout this, all free, all 100% browser based, some requiring sign up.

Server

Since the whole point of this tutorial is to hook up GraphQL/Apollo and React Native we can leverage an incredible web-based tool, Launchpad.

This will go ahead and setup our server for us, set up GraphQL, and give us an endpoint to work with. When you’re ready to make it more serious you can easily export the entire express app, with all your existing work, and you’re off to the races!

I would suggest signing in/creating an account so you can save your work.

Database

I don’t like setting up database. It’s a personal thing. It’s too serious for me. So I always offload the work to someone else. This time we’ll be using mLab to handle the Mongo database — they’ve got a free sandbox tier and that will be absolutely perfect for us.

You’ll need to sign up for this one.

A note on databases: Don’t want to use Mongo? You can still use this tutorial, just use your preferred DB and modify the queriers to work with it.

React Native

I’m going to be using Snack by Expo. It’s an incredible web-based way to build React Native apps. Once you’re done you can easily export it into your normal development flow, just like Launchpad. One suggestion I do have is to download the Expo app and use that as your development device, I find the experience to be better than when using the in-browser simulator.

I would suggest signing in/creating an account so you can save your work, though it’s not required.

Easiest setup in history? I’d say so.

Configuring the Server

The first thing we’ll do is configure our server on Apollo Launchpad. Here’s a simplified version of the server you can use to get started. If you’ve got a basic familiarity with GraphQL (which I’m assuming you do) you’ll pick up on this quickly.

In Launchpad you should now be able to query “hello” and get a response.

First thing we’ll do is setup all the necessary queries for our GraphQL endpoint. Given our basic feature spec the only query we need is one that will return a user. Just return a basic user object that has an _id and email for now.

Now let’s set up the necessary mutations, login and signup. These should each accept an email and password.

Go ahead and give it a try to make sure you don’t have any errors.

Connecting to the Database

Once you’ve set up your account with mLab and created a new mongo db instance you should see a url along the lines of

mongodb://<dbuser>:<dbpassword>@ds121665.mlab.com:21665/graphql-auth-demo-1

you’ll also need to create a user for that database (with write permissions). Take that url and add it to our “secrets” as MONGO_URL in Launchpad. Make sure to swap out <dbuser> and <dbpassword> with the values of the user you created.

By adding the secret values here we can access them from our context function, which is where we’ll be establishing our mongo connection. This context function will be called each time a request is made to a GraphQL endpoint so we want to store a reference to our connection outside of the function (allowing us to only make the db connection request once). We’ll then return the mongo variable in context so that we access it in our resolver functions.

Make sure you import { MongoClient } from 'mongodb'; at the top of your file! Launchpad will automatically install it.

Sign Up

Now let’s access the database from the resolver functions… first signup. We’ll get a reference to a users collection and then check if a user with the given email address already exists.

We can then insert the user document into the collection. I’ll be using bcrypt to hash the user’s password, because you should never store a plain text password in your database! Make sure you import the lib:

import bcrypt from 'bcrypt';

I’m going to be using async/await because it makes for easy to follow code.

Go ahead and give it a shot in Launchpad

Login

The login mutation is very similar to the one we just put together.

First we’ll check if a user with that email address exists.

Then we’ll compare the password supplied and the password we have stored. If they match then return the user!

So now we’ve got our sign in & sign up mutations working, but that isn’t all! We don’t want to force the user to have to login with every request. Enter…

JSON Web Tokens

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA.

For us this means that we can generate a JWT and use that as a means of confidently identifying a user. The flow will work like this

  1. User logs in or signs up
  2. The server returns a JWT
  3. The client saves the JWT to their local storage (covered in part 2)
  4. The JWT is passed with each request from client to server (on the Authorization header — covered in part 2)
  5. The server uses the JWT to grab the user’s information and add it to context
A note on step 5: Since I wanted to keep this all browser based we need to do this manually. If you’ve got total control over the server though you can use express-jwt to do this automatically. This is a good way to learn what that module is doing though!

The Secret

A JWT is signed with a secret value. We’ll want to come up with one and add that to the “Secrets” in Launchpad, like we did MONGO_URL. I’m storing it as JWT_SECRET with a value of super-secret.

Now, using that secret we’ll want to generate a new JWT and return it on the user object when they successfully login or sign up. First I’ll add jwt to the User type in our type definitions.

Make sure you add import jwt from 'jsonwebtoken'; to the top of your file.

Generating the Token

Then, upon successful login, I’ll create a JWT. We’re passing the user’s id as part of the payload and secrets is coming from context.

We’ll do the same for sign up.

Adding the Current User to Context

Finally (for this part at least) we need to add the current user to context.

Remember, if you’re not using Launchpad you can use express-jwt to do this automatically. I also need to note that I’m basing this function a bit off of this launchpad which does the same thing but for the Auth0 service.

First, create a new function called getUser and check if we’ve got a potentially valid authorization token in the header.

Then we’ll try to verify the token that was passed.

Then we’ll attempt to fetch the user from our database using the _id that we put into the jwt payload initially. ObjectId is coming from the mongdb module.

Finally, let’s go ahead and call this getUser function from the context function.

Header values will be lowercased

We can also update the currentUser query to return the user from context.

Let’s go ahead and check this out…

And there you have it! Runnable source code is available below

This was just the first part of this series, in part 2 we’ll connect our React Native app to it.

Part 2 is available here:

My name is Spencer. I teach people to build 🔥 apps with React Native. Interested in more high quality tutorials? Sign up for my email list.