In simple terms, authorization is the process of verifying what users have access to (after authenticating). This video assumes that you already have authentication set up and are ready to add authorization.
Authentication is the process of verifying if a user is who they say they are. After a user successfully authenticates, access JWTs are issued back to the application.
In our case of authorization, we are using the JWT (JSON web token) in our NodeJS / ExpressJS API calls, to verify the user has the correct access to the desired resource.
Tyler Clark: [0:00] I already assume that you have Authentication set up in your app already, which means you have the ability to login and logout using Auth0 in your app. Our goal today is to set up the Authorization part of it. Feel free to clone the repo listed in the video notes below to follow along with me.
[0:18] Notice this login button here. The first thing we're going to do is try to sign in. We've successfully Authenticated. Let's head over to the external API page. This is where we're going to hit our Express API.
[0:30] Let's take a moment to talk about what authorization is before we get into this code. Authorization goes hand-in-hand with Authentication. You'll probably hear these two words used interchangeably. However, authorization represents a fundamentally different function.
[0:46] In simple terms, as you see here in the Auth0 docs, at some point, your app's custom APIs will need to allow limited access to users, servers, or servers on behalf of users. An authorization is the process of verifying what a user has access to, then allowing that resource to be acquired.
[1:07] With that in mind, let's apply it to our app here. This public endpoint within our API is free for anyone to hit. There's no need to authenticate or setup authorization for this one. However, we want to restrict the resource return from this endpoint to those that are authenticated.
[1:25] This external api.js file has the code to the page we're just looking at. Here's the code for those two buttons, the public and the protected endpoints. Let's first set up the code for the public endpoint, because that's pretty straightforward.
[1:40] Both of these buttons have an onclick function already on it. If we go to this function, we'll see that we're just returning that thing right now, our undefined. Let's go ahead and update this public endpoint function to actually call the public inpoint, that we've already set up beforehand.
[1:54] We're going to say const response = await fetch. Then here, I've already defined the API. I'll show you that here in a moment. We're going to hit that API/public endpoint. Since it's a promise, we're going to .JSON on it to get that JSON value.
[2:08] Once we have that, we're going to setstate with this. I'm going to be doing show result is true, because I have a loading state. Then I'm going to use the message that we've gotten from the response data and add that to my state.
[2:19] If I get an error, I want to catch that, obviously. Then I want to store that in my state as well, so that I could handle any kind of errors, or display that to the user.
[2:27] Now, let's take a quick look at that API that I've already set up. If I look at this API origin, you see that it's on port 3001. Inside of this project, I've got an API server.js file. This is where I'm setting up Express. You'll notice that I've set that port to 3001. This is the API that we're hitting.
[2:45] You'll notice that I've already set up the api/public-endpoint here. It doesn't have any authentication or any kind of checks in it. It's just responding with the message, "You call the public endpoint." Everything works out correctly. This is what we should see on our screen on the external API page.
[3:00] I'm going to open up the console tools so that we can check the Network tab whenever I pushed the public endpoint button. I notice that when I push it, I get my message. I am successfully calling and hitting that public endpoint.
[3:17] Perfect. Now the first step in setting up the protected endpoint is going to be logging into your Auth0 account. Once you've logged in, on the left, there's going to be a site navigation. Click on the applications arrow, and then click on APIs. We're going to be creating a new API.
[3:36] Click on the big, orange button that says, "Create API." Give your API a good name. For mine, I'm going to call it Quickstart API. Then identifier, I'm going to say quickstart/API. Make sure you have the HTTPS at the front of it.
[3:51] After you've created your API, this is the screen that you're going to see here. It's going to jump into the Quickstart in the Settings tabs. You'll notice there's a lot of settings and configurations. You can do with your API to make it how you want it to work. For us, we're just going to leave it as is.
[4:07] Now without closing this tab, let's head back over to our code. Let's set up the onClick function for the protected button. I'm going to start by copying the tryCatch I did in the public endpoint function, because it's basically the same thing except for one additional step. That step is getting the access token from our authenticated user.
[4:28] We're going to do that by using this function getAccessTokenSilently from our React SDK. I'm going to update the endpoint to be protected instead of public. Then, our fetch is going to get a config object where we're going to have an authorization header. That's going to be a string bearer and then our token.
[4:45] We need to pull out this getAccessTokenSilently function from, again, our React SDK, which you can see we're pulling it up here at the top. With that saved, let's head over to our API server and set up that protected endpoint. I'm just going to copy our public, what we've done so far. I'm going to change the route to protected and just change the message.
[5:07] Next up, we need to add the authentication step, but let's see how it's working right now. As you can imagine, this is going to work by clicking the button here, because again, we haven't set up that authorization yet. It's basically just calling a public endpoint with our access token on it.
[5:24] To set up that actual authorization, let's get the value out of our Auth0 API dashboard. Make sure you're still in that API view here. In the Settings tab, we're looking for this identifier. Go ahead and copy this, because we're going to use in two different locations within our app.
[5:40] I've created a config file here that holds my Auth0 application and API values, such as the API identifier. The identifier is also called the audience. We're going to paste in the value that we copied from our Auth0 dashboard to this. We'll reference this API identifier within our API server logic, and we'll also need to pass it to our React SDK.
[6:06] Next up, let's open up the terminal and install some npm packages. That's going to help us validate our sent access tokens. We're going to be installing the express-jwt package as well as the jwt-rsa package.
[6:20] Once those install, head back over to the API server file because we need to update with these packages. We're going to bring them in at the top of this file and then start working on a reusable middleware that we can add to specific endpoints.
[6:34] I'm calling it authorized access token because that's the job of this middleware. It's going to be checking the access token it receives and make sure it validates with the audience, the identifier, the API we've set up for.
[6:47] You'll notice that we're using the two previously installed packages in this middleware. These two packages are required to be used together in order to successfully validate the access tokens it'll be receiving against the custom API we defined within Auth0.
[7:02] I'm passing through some config options such as cache, rate limit, and/or API audience or identifier, in an attempt to make sure the access token that receives is valid against my API. Once I'm done writing it out, you'll notice that I'm passing this middleware to my protected route.
[7:19] Awesome. Now let's try it out and see if we got it working. I'm going to click on the Ping protected endpoint. You notice that I do successfully get my call. I'm getting my called protected API message back, and that is what's displayed on my screen here.
[7:35] If we look at the headers and look for that authorization header that we've put on to this request, you'll notice that it's got the bearer and then the long text here. This is our access token. If I copy this and go to JWT.io, you can see what's on this access token. This is what's getting passed through to our middleware, and it's validating that this is a correct access token.
[8:01] To make sure that we're doing everything correctly, if I comment out our headers here and then go back to our app and try it again. You'll notice that we get an error, because we're no longer passing that access token on the authorization header, and our middleware is catching that and throwing it unauthorized.