This course has been updated! We now recommend you take the Server-Side GraphQL in Node.js course.

Check out a free preview of the full Introduction to GraphQL course:
The "Authentication Exercise" Lesson is part of the full, Introduction to GraphQL course featured in this preview video. Here's what you'd learn in this lesson:

Students are instructed to authenticate a request, and block requests when appropriate.

Get Unlimited Access Now

Transcript from the "Authentication Exercise" Lesson

[00:00:00]
>> Scott Moss: This exercise and this one's actually really fun. So I like I said, there's many ways to authenticate with GraphQL. Our API is public, so we'll use API keys. Some queries need authentication, and some queries also need the correct role. So authenticate the request and update the product resolvers.

[00:00:18] So what do I mean by that? So check out the lesson five branch. And basically, what you're gonna do is you're gonna authenticate the request and add the user to the context object. You're gonna block all product queries and mutations if there is no user. So you're gonna check for a user in a context object, and I'm gonna show you what that means.

[00:00:38] But if a user's not there, you're not gonna throw an error, you're just gonna attach it to the context object and you just go. In the resolvers is where you check and see if the user's there or not. So every single query has to have a user on the context object.

[00:00:52] If it's not, it should throw an error. For mutations, not only should there be a user, but that user should have a role of admin. If the user doesn't have a role admin inside the mutations, it should also throw an error. And then, once you do that, all your tests should pass.

[00:01:05] So basically, you're gonna go back to the product resolvers that you already created. And you're going to change the queries to check to make sure that there's a user. Then you're gonna change the mutations to check that there's a user, and if that user has a role of admin.

[00:01:19] And then if that's true, then you can proceed. If not, you're gonna throw an error. That's it.
>> Scott Moss: So if we check out, if we go back to our repo,
>> Scott Moss: And we check out to lesson five.
>> Scott Moss: One thing I wanna show you is if you head over to Server.js, this is where I say you're gonna add the user to the context, this whole time I had in the context object, we get this request.

[00:01:51] And we get this user user :null, all right? There is a note here that says use the authenticate function from utils to Auth the request. And it says it's Asynch, as in the authenticate function is Asynch. And remember, this context object can be asynch so you might have to add a little async here, do like some stuff here cuz the authenticate function is async.

[00:02:12] So the authentication function is already done for you. You don't have to do anything but to check it out. Utils off. It's this function right here. It takes the entire request object, looks for an API key, if it does have an API key, it will find the user and return it.

[00:02:28] If it doesn't have an API key, it just returns nothing. It doesn't error out, cuz we want the reserves to do the error handling. We want the reserves to do the error outs. We don't want the server stopping if it is not authenticated. So we're not gonna do that here.

[00:02:39] So this is gonna return nothing. So we're gonna use this function inside of server js here to attach the user here. So instead of attaching null, you're gonna to attach whatever authenticate returns. That's what you're gonna attach. So that's step one. Step two is going over to the product resolvers and updating the two queries that we have, product and products, to check for context.user.

[00:03:03] If there is no context.user, then you need to throw an error. And the error that you have to throw is this authentication error that ships with apollo-server. It's just a fancy error that they created that just tells the client that you're not authenticated, that's all it is. It's just an error class that they extended.

[00:03:18] You can make your own error class, but the test is looking specifically for this authentication error, so you have to throw that error. So this throw new authentication error if the product or products doesn't have context dot user. And then, the third one is what you need to do is for all the mutations like new product, update product, and remove product, not only do you need to check to see if there's a context dot user, but you also need to check if that context dot user dot role equals admin.

[00:03:43] And if it doesn't equal admin or the user is not there, then you also need to throw an authentication error. Cuz we wanna make sure that only admins can create, delete, and update, but every authenticated user can read. So that's what that's for. And once you have all that, all your tests should pass.

[00:04:01]
>> Scott Moss: Any questions on that? The test command you wanna run is gonna be mpm test off.
>> Scott Moss: So yeah, just run that test command, you'll see some failing. You should see about six test failing here for authentication. And you can see that, even in a test it's saying expect that the functions to throw a type error of authentication error.

[00:04:31] But it didn't throw anything. So it's expecting that. Sojust follow those tests. Do those checks. I recommend doing those checks for users as the first thing on your function. That's the first thing you should check for. Don't even proceed to the database unless those checks pass. And just throw your errors.

[00:04:48] You don't have to catch them, just throw them.
>> Speaker 2: As far as the only made product and interface, did we have to update our new product code now because of-
>> Scott Moss: Nope, you don't have to do anything, that's the beauty of it, yeah. It's treated just like a type, it's an abstract type.

[00:05:04] It does the same thing a type does except you just can't query for it, it has to resolve to some other type. But as far as the resolvers and stuff? No, you don't have to change anything. Because if you look at your schema, your queries still return a product, right?

[00:05:19] So your resolvers still return a product. Nothing's changed about it. It's still got the same fields and everything on it. It's just now that it's interfaced. So you don't have to change any of that.