Add the User to the GraphQL Context Object
Ryan Chenkie: [0:00] You might recall that in our typical setup for this application, for the express API, we are hitting some JSON data endpoints, and we have typically been using a set of middlewares to check for things like the authorization header on the API, to decode the token premise, and then eventually pass that on to our endpoints, and we also use middlewares to verify the JSON web token.
[0:22] The way that we do this in GraphQL looks a little bit different. Let's come into our API, we'll go to Orbit API and to Server.js, and let's take a look at our resolvers here. We can look at our first resolver, which is dashboard data. This is kind of the endpoints that we get to before we return some dashboard data to the browser.
[0:42] Now, GraphQL resolvers have four arguments. We've got parents, which is going to be information above the query that is the parent to this one. We've got args, which will be any arguments passed in on the query. We've also got context, and then we've got info. Context is a place where we can keep things like the authorization header, or even the user's information.
[1:04] The info argument here is a little bit more advanced. Info exposes a GraphQL AST which allows us to manipulate things about the query and do some cool stuff, but it's a little bit beyond the scope of this course. For now, we're just going to stick with these arguments.
[1:19] If we do a council.log on context, we can get a sense of what it looks like. Let's open up the terminal and we'll go over to our node API, and then if we refresh over in the application, we can see that context is this object that's got extension stack, which looks like a private thing from GraphQL, and then something about extensions.
[1:41] This is just some default configuration that comes on context, but we've got the opportunity to stick anything on context that we want, and this makes it really useful for things like authorization information, because we can then use it anywhere in our resolvers that we might want to. The spot where we can configure context is where we create our Apollo server.
[2:00] Let's go all the way to the bottom here, where we new up our Apollo server, and as an option here, right after resolvers, we can pass context. This is going to be a function which is going to have a request parameter here, and we can destructure that out.
[2:15] Just to get a sense of how this works, let's do this. In the body here, let's return an object and we'll say name is equal to Ryan. Let's save that and then over in the application let's refresh, and up at our dashboard data resolver, we're logging out the context and now on the context we've got my name.
[2:36] This is a good spot for us to verify the JSON web token that's coming in on request, and here we can also pass along the user data that comes from the token. The user data is found in the payload, so we can get the decoded payload and we can stick that on context.
[2:51] We're going to use a package called JSON web token to verify the token, and we are going to bring it in like this. const JWT equals require JSON web token. Now this package should already have been installed because it's being used in other places. Just make sure that you've got it. If not, you might have to do an MPM install JSON web token.
[3:11] Back down in our Apollo server instance, let's use that to verify the token. Within context here we can do our verification. One way to do this with the JSON web token package is going to be with a Try-Catch blog, so we can do Try- Catch, and let's try to get our token off of the request header.
[3:31] Let's say, const token equals request headers.authorization, and remember, this request here is just the express request that we've been seeing before, and that express request object has a header's object, and it should have an authorization header on it. If it doesn't, it means the user is not authenticated, so let's do a check for that first.
[3:51] We'll say if there's no token in place...if there's no token coming on the authorization header, let's just return user-null. If there's no authorization header, we assume there's no valid user. However, if we get past that point, we can try to get a decoded token, and to do that we can say JWT, and we will pass in our token.
[4:14] We've got our token coming in with the Bearer scheme, so again we'll do token.slice at index seven. That's going to take everything from index seven and beyond, and that will just be the value of the token, and then we want to run that verification against process.env.JWT secret.
[4:31] If that's good to go, what we can do is say return user is the decoded payload, and if you need to refamiliarize yourself with how the user comes in the decoded payload, review the section on JSON web tokens in the React Security Fundamentals course.
[4:48] If there's an error, if something went wrong, let's assume that there's no good user and we won't be able to authorize the request, so if there's an error, we can say return user is null so to check that this works, why don't we go back up to our dashboard data resolver, and we can try to get the user off of the context here. Let's say console.log context.user.
[5:11] If we refresh in our application here, we've got null coming through, and so let's see what's going on. Let's review our context here. Let's try logging out the error to see if there is one, console.log error, and we will refresh again...it looks like we do have an error, and it says JWT is not a function, and it looks like the issue is we have to call JWT.verify.
[5:36] When we're using the express JWT middleware, it's just a matter of passing in some arguments to JWT, but in this case, since we're using the JSON web token package, we have to call JWT.verify. Let's save that and we'll try again, so coming down to the bottom here, if we refresh, we're now getting our user logged out from the dashboard data resolver.