GraphQL resolvers have an argument called "context" which is shared between resolvers and can be used to store authorization information, database connection information, and more. Learn how to use the context argument to get authorization information from a JSON Web Token. Use the authorization information to scope the data sent back in the resolver to that which belongs to the requesting user.
Ryan Chenkie: [0:00] This GraphQL server has a single type of order. We've got a single query where we get a list of orders. We have some orders data with a clientId. We've got one resolver to get those orders out. Run the query and we get all of that data back.
[0:16] The idea here is that this data should really be scoped to whoever is making the query. Whichever user is logged in to the application, the data they get from this query should be relevant to them.
[0:27] For demo purposes, we can use this clientId to be the key that we filter based on. We don't want to send back all of the data for anyone who makes this query. Instead, we want to limit it to who the data belongs to.
[0:39] To help us do that, we will use the context argument. GraphQL resolvers have four arguments. The first is parent. The second is args. The third is context.
[0:51] This context argument gets shared between all resolvers in your GraphQL server, and it's useful for putting items that are needed for any given resolver. Things like authorization data, things like database connections and more can go here on context.
[1:05] We can see what it looks like if we do console.log(context), and then just continue to return the orders. Execute the query again. We see that we've got this object with some information that's particular to the server.
[1:21] We can set our own particular data on context down here in the server setup. Put in the new key called context. That's going to be a function that returns an object. We can put whatever we want here. We'll put maybe clientId of two.
[1:36] If we run the query again, now we've got clientId two coming through. Filtering becomes pretty simple. We'll do orders.filter. We'll take an order and we will return order.clientId === context.clientId.
[1:55] Run the query again and now we just have that single order coming through. Hardcoding the value in like this definitely isn't very useful. Instead, we need to get authorization data like this from somewhere else.
[2:07] That somewhere else is going to depend on how you have authentication and authorization set up for your application. Some common ways are to use JSON Web Tokens or cookies and sessions.
[2:17] We can get an idea of how to do this if we use JSON Web Tokens. Go over to jwt.io. Down in the debugger, go to the decoded tab. In the payload, add in a key of clientId, and set that to one.
[2:35] In the signature verification portion, put in a secret key, maybe something just like a secretkey. As you can see here, it's saying here, "Weak secret," so please do not use this in production. This is just for demo purposes.
[2:47] In the encoded tab, we can grab this token. Back over in the playground, we can use this in an authorization header. Add in a JSON object. The key will be authorization. The value will be bearer, space, and then the token.
[3:06] This is a convention. Often, you'll see this when using JSON Web Tokens, is that the scheme is set to bearer. To pick up this header, we'll do that in our context function. We can destructure out the request. This is an object representing the request that comes in.
[3:22] That's going to come in on every request that we get to our server. Now, clientId can be set with something else. Maybe we'll give a function called getClientId. In here, let's pass in the request headers authorization.
[3:38] Let's define that function up here. We'll say const getClientId is equal to a function that takes a token. This is where we need to verify the tokens, so that we can make sure that it's actually usable. We can do that with a library called JSON Web Token. Do npm install jsonwebtoken.
[3:59] At the very top now, let's pull it in as a require, so const jwt = require jsonwebtoken. Down in the function that we're creating here, we can now say const decoded = jwt.verify. We'll pass in the token. We need to cut out a portion of this because the verify function isn't expecting the bearer portion to be at the beginning.
[4:25] What we can do is, say let's slice that string at index seven and we'll keep everything afterward, just the token portion. The secret that we used was secretkey. Once again, please, please, do not use this for production. This decoded object now is just a payload of the token, so we can return decoded.clientId.
[4:48] Run the query again. Now, we've got clientId 1 and these orders here represent those that belong to clientId 1. The source of truth for claiming that clientId is coming from the JSON Web Token, which by its nature, we can trust, as long as the authorization step to actually create that token happened appropriately.
[5:08] There's a lot of detail around that particular subject. As long as we can verify a token, we can generally trust the payload that it contains and use that in our application to make decisions about how we query for data.