Advanced GraphQL, v2

Authenticated Helper Solution

Scott Moss

Scott Moss

Superfilter AI
Advanced GraphQL, v2

Check out a free preview of the full Advanced GraphQL, v2 course

The "Authenticated Helper Solution" Lesson is part of the full, Advanced GraphQL, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Scott live codes the solution to the authenticated helper exercise, and answers questions about data validation and authentication.


Transcript from the "Authenticated Helper Solution" Lesson

>> So first things first, let's build out these functions. So the authenticated function, so if you check out the comments right here, and kind of like the description of what I gave you, it says text if the user is on the concepts object continues to the next resolver if true.

And that's basically it. So what we can do is we can say if context.user or actually better yet, we can say if not context.user, then what we are gonna do is just throw an error. And don't worry about errors right now on GraphQL we're gonna get to that later but you can just throw an error, not authorized, like that.

If you are, then we wanna return the next resolver. And it's important that you put return here, because the resolver is gonna return a value. If you don't return it, it'll execute it but the value will always be undefined because if you don't return inside of a function, it's always undefined.

So make sure you put that there. And then we'll just copy all of these arcs, like that. There we go. Pretty simple for that, and then as far as the authorization, this one's pretty much the same except for we're checking for a role on an authenticated user. So it checks that the user on the context has the specified role, continues to the next resolver if true.

So if not, context.user.role or if context.user.role does not equal the role that was passed, then were gonna throw an error. Must be a whatever that role is, There we go. And if good, we'll just say next, return that and pass all these arguments like this. Cool, everybody following me so far?

All right, simple enough. Okay, so now we're going to our resolvers and we just need to wrap all the stuff starting with me. So with me cuz it's returning yourself the user, and we get the user again from the context object which is trading a token, a possible token for user.

So this may be null, it may be a user, we don't know. And that's what the authentication function helper is doing. It's checking this user on the context object to see if it exists or not. That's the responsibility. So we wanna do that for everything that involves a user.

So in our case, me so we can say authenticated here, convert this to arrow function like so. And now we have me. So to check this out, if I go and start a server, Go back to Playground. I think I already have a JWT in here that should still be good.

So if I get rid of this JWT, and I try to execute this I'll just get an arrow saying not authorized. So that's good. If I add the JWT back, I should, I guess I did. It's not good anymore, I'll sign up, let's sign up for one right here.

So that's the variables in here, so cool. So let me sign up, get this token. Go back, replace this token with this one, like that. And now if I do it, I get back me and get the email all that stuff. All of it just works, right? Pretty cool, so you did the same thing for posts.

So we come here and we say authenticated arrow function. We do the same thing for this one post. Wanna get all of them in here, userSettings using so we'll do that too. Make sure you're not getting someone else's settings and just yours. Feed is public, so we won't wrap that.

Update your settings for sure, you got to be authenticated, update your own settings. To create a post, yep, we only want authorized users creating posts on our little network that we have, our authenticated users. Update yourself, definitely got to be authenticated. Invite, so this is a special one.

So invite is not only do you need to be authenticated, you need to be authorized to do this. So in order to do this, we need to do a couple things. One, we'll look at the auth sure, you could have come in authorize and also check to see if context.user exists and then you can just have one function.

But I like to keep each function responsible for its own job. So this is not the job to check to see if the user exists, although it will error if it doesn't. It's the job to check to see if the role in the user is correct. So that means we need to first check to see if you're authenticated like this.

And then we need to also check to see if you're authorized like this. And authorize, this takes in one argument. In this case, it's gonna be the admin like that. Now you have to be an admin to be able to invite. So if you wanted to try that out, I believe my user is a, it's a member, so I have that one member I'll make.

Let's see, member, Of course, now I have a member one, I'll grab that and then I'll try to do an invite. So if I said I'm just gonna do a shorthand mutation here, invite, take some inputs, what does that say? I got email. I think it also takes a role maybe, yeah.

I'll just put, invite a member here. Try to get this back and at my headers for authorization, With the member JWT, and if I try execute this, must be an admin. If I go back and grab my app JWT that I have here and try to do invite, We get it, it works.

So super clean, very simple, just makes sense. And then for sign up and sign in, we definitely don't wanna lock those down because no one would ever be able to sign up and sign in. So don't ever do that. And then we have these few level resolvers. So because these few level resolvers are resolved after types which are usually resolved on the query level, we don't necessarily have to authenticate these fields.

Although there may be different scenarios where you can like for instance, I'm not exactly doing an authentication here. But I am checking to make sure that the posts on the user that you're trying to get, that belongs to you. So this will prevent you from looking at any others user's post.

And that's because the way that this graph works is you might be able to go look at another user object through the post type. So if I were to go look at a post, a post has an author field on it, which is a user type, that user who created that post might not be you.

And if I don't catch this, you might find a way to look at some other user's post through the connection of, you might find another way to look at another user's post through a post. So it's very complicated but this is not, technically authentication is more like locking down information that isn't yours.

It's like a multi-tenet thing. So we're not doing authentication or anything like that but you could do authorization. I guess, you can think of this as some sort of authorization. It's not so much of a role but are you the user of these posts? So you could use your authorization helper here.

So let's say there was a field on settings that had payment info, had a payment or a subscription info or something like that. And you don't wanna show that to every person in your organization. So you will lock that down to only admins can look at, the subscription info and a payment last four and stuff like that.

So you could lock it down on that field level, that most of the time authentication is gonna happen on the query mutation level.
>> Is there any advantage to using the method an exercise over using schema directives?
>> Man, that's such a good question. So we're gonna get the schema directives later today, and you'll have the opportunity to make authentication directives.

And the advantage is, you don't have to rewrite this, you won't have to wrap every single resolver every single time. You can write one directive and it'll wrap any resolver you want it to without having to repeat yourself. So your code will be a lot cleaner. But the actual implementation is 90% the same of what you just did.

You just have to write some code to tell GraphQL to how to do it. So obviously, the other benefit is that you just have less code, and it's easier to modify. And it just looks cleaner honestly.
>> Is it possible to do a data validation using this method that is using the authentication?

>> Yeah, you can do data validation. So I'm guessing what they're describing is some input arguments. And you wanna validate that those inputs are what they are outside of what's capable what GraphQL input types which are checking just to see if something is a string or something is a integer.

But you wanna check to see if something is greater than this or less than that. Yes, that's a really good approach to do that. You could definitely wrap your resolvers to check for those inputs. If you could just think of that process of what we did is basically like creating middleware for your resolvers and applying that middleware to any resolver you want.

So inside of that context, sure, you can do whatever you want and checking inputs for different values and stuff like that, it's a great place.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now