This tutorial is out of date and no longer maintained.
Warning: This tutorial is out of date and no longer maintained. It is based on Prisma 1 which is not actively developed any more. To learn everything about the latest version of Prisma, visit the official Prisma documentation.
If you want to learn how to build server-side applications with Prisma, you can follow these new tutorials:
In Part 2 of this series, we covered how to generate a temporary token for our user whenever they log in or create an account. Now we’re going to wrap it up by restricting our data to only certain authorized users.
When we create a token, we’re going to be giving it our user’s ID and then use that ID and jwt.verify
to return data pertaining to that user if the verification was successful.
The first step is to set up our context to handle the headers from the user’s request. If we change our context
parameter to a function, it will automatically have access to our request as an argument.
const server = new GraphQLServer({
typeDefs: './schema.graphql',
resolvers,
context(req) { return { prisma, req } }
});
Now we should be able to destructure the req
object out of our context. If you try logging req
you’ll see that there is a request.headers
which will contain the authorization
we passed into the GraphQL Playground. This is what we’ll give to jwt.verify
with our secret to check if that user is valid. Since we’ll be doing this for every resolver we want to secure, let’s make it a function.
It’s pretty straightforward; we’re just getting our token from the header, removing Bearer
, so only the token is left, verify it, and return our user’s id.
const getUser = req => {
const authorization = req.request.headers.authorization;
if (!authorization) throw new Error('Authentication Required');
else {
const token = authorization.replace('Bearer ', '');
const user = jwt.verify(token, process.env.TOKEN_SECRET);
return user.userId;
}
};
Let’s add a few new resolvers into our schema first. We’re just going to practice with a currentUser
query, deleteAccount
and updateUser
mutations, and a myAccount
subscription.
type Query {
users: [User!]!
currentUser: User!
}
type Mutation {
createUser(data: CreateUserInput): User!
loginUser(email: String!, password: String!): User!
deleteAccount: User!
updateUser(data: UpdateUserInput): User!
}
type Subscription {
myAccount: AccountSubscription!
}
type User {
id: ID!
name: String!
email: String!
password: String!
token: String
}
input CreateUserInput {
name: String!
email: String!
password: String!
}
input UpdateUserInput {
name: String
email: String
password: String
}
enum MutationType {
CREATED
UPDATED
DELETED
}
type AccountSubscription {
mutation: MutationType!
node: User
}
Authentication is now going to be incredibly simple; just get our user’s id with getUser
and pass that to where
. Now it will return data for the user that’s logged in and only that user.
const Query = {
users(parent, args, { prisma }, info) { ... },
currentUser(parent, args, { req, prisma }, info) {
const userID = getUser(req);
return prisma.query.user({ where: { id: userID } }, info);
}
};
Mutations are just as easy, except with updates, we’ll want to check if they’re changing their password first since we’ll need to rehash it first.
const Mutation = {
async createUser(parent, { data }, { prisma }, info) { ... },
async loginUser(parent, { email, password }, { prisma }, info) { ... },
async deleteAccount(parent, args, { prisma, req }, info) {
const userID = getUser(req);
return prisma.mutation.deleteUser({ where: { id: userID } }, info);
},
async updateUser(parent, args, { prisma, req }, info) {
const userID = getUser(req);
if (typeof args.data.password === 'string') args.data.password = await bcrypt.hash(args.data.password, 10);
return prisma.mutation.updateUser({
where: { id: userID },
data: args.data
}, info);
},
};
Subscriptions are just as self-explanatory once again, just remember to add Subscription
to your resolvers in index.js
.
const Subscription = {
myAccount: {
subscribe(parent, args, { prisma, req }, info) {
const userID = getUser(req);
return prisma.subscription.user({ where: { node: { id: userID } } }, info);
}
}
}
That may have seemed like a lot of work, but using authentication is by far the easiest part of the process. The important thing is to understand how it works, even though you’ll most likely use a starter boilerplate for most of your real projects.
Warning: This tutorial is out of date and no longer maintained. It is based on Prisma 1 which is not actively developed any more. To learn everything about the latest version of Prisma, visit the official Prisma documentation.
If you want to learn how to build server-side applications with Prisma, you can follow these new tutorials:
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.