Authentication in Prisma - Part 1: Setup

Joshua Hall

Unless if you’re using something like Firebase to handle your authentication, it can be a bit tricky to handle it in a way that is both secure and easy to manage. In this three-part series, we’re going to be going over how to setup your GraphQL API for handling authorization, generating tokens, and securing your Prisma data from the outside world and against unauthorized users.

Prerequisites

You’re going to need to have a basic Prisma container setup and connected to some database, in this case, I’ll be using the Postgres setup from this article.

If you don’t want to worry about the Prisma setup, you can copy this repo to get started. Just remember to move into the prisma folder and start a new Docker container.

$ npm install
$ docker-compose up -d -e ../.env
$ prisma deploy
Recommended React and GraphQL course

Setup

After you have the starter boilerplate cloned, your folder structure should look something like the following. You’ll need to add a new env file with your database credentials, and another which should be in the root of the project since we’ll be storing some secrets that Node.js will need as well.

* prisma 📂
  * .env  -For database credentials
  * datamodel.graphql
  * docker-compose.yml
  * generated.graphql
  * prisma.yml
* src 📂
  * index.js
  * prisma.js
  * resolvers.js 
* .babelrc
* .env  -For Secrets
* .graphqlconfig
* package.json
* schema.graphql

Since we’re going to follow best practices and use env files for our important/secret information, we’re going to need the env-cmd package to get node to look at it before running anything.

$ npm install env-cmd --save

Closing Off the Server

Currently, if we were to deploy our API as is, anyone would be able to read and write to our production database through Prisma. The first thing that we need to do it block any operations that don’t come with a valid authentication token, which we’ll add later.

The first step is to add a secret that any user will be forced to provide to interact with the API, which is best for us to add as an environment variable.

prisma.yml

endpoint: http://192.168.99.100:4466 # or http://localhost:4466 
datamodel: datamodel.graphql
secret: ${env:API_SECRET}

For now it doesn’t matter what it is, I’ll just be using a string but you can use a token generator if you want.

.env

API_SECRET=SuperSecretSecret

When we redeploy we need to tell Prisma to look at our env file first by using the -e flag directing it to the correct file. It already uses the one in the same directory by default, we have to be explicit about files anywhere else.

$ prisma deploy -e ../.env

Now that we have successfully broken our app, an attempt to use our Node.js connection should fail. A query should return a response like "Your token is invalid. It might have expired or you might be using a token from a different project.". To give it access, we first need to pass our secret to our Prisma instance.

prisma.js

const prisma = new Prisma({
  typeDefs: 'src/generated.graphql',
  endpoint: 'http://192.168.99.100:4466/',
  secret: process.env.API_SECRET
})

And finally, just tell our start script to look at .env before running nodemon.

package.json

"scripts": {
  "get-schema": "graphql get-schema -p prisma",
  "start": "env-cmd .env nodemon src/index.js --ext js,graphql --exec babel-node"
},

For me, env-cmd versions 9+ kept throwing the error 'This file does not have an app associated with it ...". As of this writing, this is still an open issue some users are getting, if this happens to you I recommend trying version 8.0.2 instead.

The final step is to tell our get-schema command to look at our prisma.yml instead of the endpoint, since that would require the secret. We can do this by making a small addition to .graphqlconfig to look at prisma.yml instead.

.graphqlconfig

{
  "projects": {
    "prisma": {
      "schemaPath": "src/generated.graphql",
      "extensions": {
        "prisma": "prisma/prisma.yml",
        "endpoints": {
          "default": "http://192.168.99.100:4466/"
        }
      }
    }
  }
}

Now that Node has access, all of your interactions with Prisma should be done exclusively over there. If you need to play with the GraphQL Playground or the server itself you can generate a token to pass in the header.

Run this and copy the token it outputs.

$ prisma token

Now in the bottom left of the GraphQL playground you should be able to open an HTTP HEADERS panel that accepts JSON. It just needs the property "Authorization" with the value "Bearer YOUR-COPIED-TOKEN".

GrahQL Playground screenshot

Passwords

Now we can get more into the fun stuff. Obviously our users are going to need an email and password to login with, so let’s add them now in both the datamodel and schema.

datamodel.graphql

type User {
  id: ID! @id 
  name: String! 
  email: String! @unique 
  password: String!
}

And don't forget to deploy and regenerate the schema!

schema.graphql

type User {
  id: ID! 
  name: String! 
  email: String! 
  password: String!
}

Testing

Let’s add a query for all users, if all went well you should be able to create a user on the Prisma API and see it on your Node server.

schema.graphql

type Query {
  users: [User!]!
}

resolvers.js

const Query = {
  users(parent, args, { prisma }, info) {
    const users = prisma.query.users(null, info);

    return users;
  }
};

Closing Thoughts

Continue to Part 2 to learn about creating tokens for our users whenever they login or create an account.

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#