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
Alligator.io recommends ⤵
👉 Fullstack Advanced React & GraphQL by Wes Bos
Go fullstack and learn things like Next.js, styled-components, Apollo GraphQL and building a Node GraphQL backend by building a real world clothing store app.
ⓘ About this affiliate link
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.
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"
.
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.