Advanced GraphQL, v2 Authenticated Helper Exercise
Transcript from the "Authenticated Helper Exercise" Lesson
>> You're gonna create an authenticated helper. So if you head over to the auth file, you're gonna see a lot of stuff happening here. But the two things that you're gonna be concerned about is this blank authenticated function and this blank authorized function. So the first task is to create an authenticated helper.
[00:00:17] So what this function does is it takes in a resolver, this next thing here is an actual resolver. It's gonna take in a resolver as an argument, and it's gonna return a new resolver. But before it returns the new resolver and actually executes it with these arguments, it's going to check to see if a user exists on a context or not.
[00:00:35] That's basically it. So if there is not a user on the context objects, it's gonna throw an error. If there is a user in the context object, it'll just call the next resolver with the given args that it got. That's all it does. From there, you're gonna create an authorized helper, which is very similar to the authenticated helper.
[00:00:53] So the authorized helper takes in two arguments, it's gonna take a role and it's going to take another resolver. And its job is to check to see if the user on the context object. So it's assuming that the user is already authenticated if the user on the context object has a role that is equal to the one that was passed in.
[00:01:11] If it doesn't, it throws an error. If it does, it just calls the next resolver with the given arguments. That's it. And then I'm gonna show you how to actually use those. And then you need to wrap the resolvers that use the users for DB quarries with the authenticated helper and the authorized helper.
[00:01:31] So if we go back to our resolvers, basically what I was saying is if you look at any resolver in here that's using a user for any database interaction, it probably needs to be wrapped with the authenticated resolver. So when I say wrap, if you look at the syntax of these functions here, they're a function that takes another function, right?
[00:01:53] So the way that you would use them is you would just wrap a function. So in this case, if I wanted to say I need to authorize me, I would come here, they're already imported up top, so let's take authenticated. Now we'll say me, actually it needs to be wrapped by authenticated first, and that's gonna take a callback, like that, and then parentheses there.
[00:02:15] So that's how you would wrap it. So I'm gonna wrap this resolver that I already have with the authenticated helper, right? And then authorized helper is very much the same, except for, remember, it takes a first argument here of some role that you need and then it takes the resolver.
[00:02:31] So that's what I mean by wrap. As far as what you're gonna use on the authorized one, there's one down here that says admin role. This is the only resolver that you should have that requires the authorized helper, and there needs to be a role of admin. And the role of admin, if you look at the type definitions, is an enum, and it looks like this, all caps ADMIN.
[00:02:54] So that's the role that you need to prevent, that's a role that you need to check for inside the invite helper here. So when you wrap this, remember two things. The authorized helper is already expecting the user to be authenticated, so you might have to wrap it twice.
[00:03:13] You might have to say this resolver is authenticated and it's authorized. And remember, these are just functions that return another function so you can put one inside of another one and they should just work. You just gotta figure out what order do you wanna do it. Are you authenticating first?
[00:03:26] Are you authorizing first? Are you authorizing first? Are you authenticating first? I think you'll figure it out. Once you have that, what you can do is, not there yet, start your server. So I'm gonna start mine, yarn dev. Whoa, I already have it started somewhere. Guess I got it in this tab, yeah, I already have it in this tab right there.
[00:03:46] Let me restart to access to demo one, and I'll do yarn dev here instead. Cool, so 4000, Go over to Playground. And now if I try to access me, because I think in my example, I went ahead and wrapped it. So let me save that. So I wrapped the me query as being authenticated.
[00:04:10] So if I try to do that, and right now I'm just gonna go into the authenticated helper and I'm just going to throw an error. And if I try to execute this, I get that error back. Nope, because the authentication helper said, I couldn't do it, right? In the case where you were authenticated, and everything just worked, and I called next with all these args, And I asked for me.
[00:04:47] It didn't error on authentication, but it's still broke because technically the context function didn't provide a user because I didn't authorize it in the context object. Cuz I didn't give in a JWT, so it doesn't know what user you want. So although it didn't break on the resolver level, as far as you're not authorized, it doesn't know what a user is because I didn't set up a JWT in the context object.
[00:05:16] Here it's looking for a JWT to figure out who the user is, so this is null. And then when I went to the resolver, it's returning user, which is null, so it's just returning null. So that's why this broke, cuz it's saying cannot return a non-nullable field me.
[00:05:31] But it is null because I didn't set up as a JWT. So that's what I was saying. You get to the flexibility of locking down a resolver when you want to, even though the user's null. So you can do that, test out your stuff that you authenticated. When you want to authenticate, there is a sign up method.
[00:05:49] So you have to use a mutation here, like Signup, and you can say signup. And you wanna get a token, and maybe get the user and get an ID if you want here. And we'll make a variable called auth, which is gonna be a signupInput type, like that.
[00:06:14] And nope, nope, failure. Go to Query Variables here, Make a object here called auth, Or let me add this here. I think this takes a input, we'll call that auth, there we go. And I think it takes email, and we're gonna say email@example.com, and it takes a password.
[00:06:53] So you can sign up like that. What is this saying? And these are role too. Yeah, you can sign up with your own role, how cool is that? Make it a admin, I'm an admin. You hit that, and the you'll get back this response here, which will give you an adjacent web token and a user ID or whatever you want.
[00:07:12] So if you wanna issue authorize request once you've set up your resolvers, you can copy this JSON web token. And you could just add it on your HTTP headers as authorization, like this, so Authorization. Actually, I'll go back here to the me query. So if I add that back to the me query as Authorization, You just paste it in.
[00:07:40] And I were to issue this authorization when you, sorry, that was query, it wasn't headers, there we go. Auth, my god, my keyboard. There we go, Authorization. So when you set your stuff up, you should see your user come back, if you were to authorize with the JWT.
[00:08:13] Cool, so just to recap what you're gonna be doing. You're just going to create these two helper methods. And then you're going to wrap the resolvers that are using any users in the database queries with those helper methods. And then the one helper method that needs authorization is the one that's called invite that has an admin role, so you need to wrap that as well.
[00:08:35] That also needs to be wrapped in authentication. And you can just check them out in GraphQL Playground.