Auth by Example with JWT in Vue + Express

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys Wes here in this video we're going to be looking at securing the back end of an application using asura so I've been getting a ton of questions lately related to JW TS and auth in general and so I want to make a two part video series that just goes in-depth looking at a practical example of off and protecting some back-end endpoints we'll look at user authentication we'll look at how to wire all this up together and then in a follow-up video we'll do a deeper dive into JWT s in general and explore some of the key concepts that you'll hear about in authentication and authorization so things like ID tokens access tokens refresh tokens what some of the algorithms and the protocols are that we'll follow up in a second video in this first video I just wanted to take a really practical approach looking at how we can create a view j/s app and interact with an express back-end and actually secure our back-end using auth0 it actually won't take us very long to set this project up and I think it'll be a really good learning resource if you enjoyed deeper dives into things like web development software engineering in general machine learning and DevOps then be sure to subscribe for more videos like this in the future with that let's take a look at our application okay so for the purposes of this demo I've already pre-built some code and I've pushed it up to a public github repo that you can find at github.com slash productive - dev slash auth 0 - demo and you'll find that this repo contains two projects that contains a demo dot client project this is our view j/s application and it also contains a demo server project which is just a bare-bones Express application it contains two routes a public route and a route that requires some authorization which will look at momentarily so just to demonstrate how you can pull this project down from github I'm just going to clone it into a project directory so here I'm just going to run git clone and then pull down that repo then I'm going to CD into that directory and then as mentioned we can find those two different projects here so first of all let's just go into the view Jas application and now we can run yarn install and this is simply going to look in that package JSON file and install all of the dependencies that are required for this project okay so once that's complete we can run yarn serve this is going to start up our view application on port 8080 now note that we're not running that back in Express API yet and so our front-end application won't actually be able to fetch the data that it needs but nonetheless it should be able to start and we can actually take a look at localhost port 8080 and so you'll find we just have a bare-bones application here we have two pages in our app we have a home and then we have a notes page and you'll note that we're not actually getting any data back here in fact if we inspect when we take a look at the console here we'll find that we are getting a network error because we're trying to make a request to an API which is not currently running so we'll leave this open and then in a new terminal window or in my case I'm using T MUX so I'm just going to open up a new pane here we're going to go into that demo server subdirectory and here we're going to run NPM install and now we'll run NPM run start and this is going to start up our Express API what you can see is listening on port 8000 so now let's head back to our browser and if we just refresh the page we can see that we're getting those responses back or rather that single response back from the public route and we are seeing some public notes here so these are coming back and then view is just rendering them into these bootstrap cards and if we take a look at the network tab we can say we can see here that it's making a request on port 8000 slash API slash public notes and we're getting back this JSON object that were then rendering into our front-end components here now if I select request private notes you can see what's going to happen is that we get this unauthorized response back in the browser which is manifesting as a toast here saying that we cannot view private notes rather and if we take a look at that HTTP request here we can see that it's in fact telling us that we're unauthorized because we have a malformed JWT so now let's select sign in and you'll see we get taken over to auth0 we have this pop-up and I'm going to simply log in once I've logged in I'm going to be redirected back to the home page in our application and now that I'm logged in you can see that we have a message out to this part of the page that says we're logged in and I'm displaying an ID token and an access token and these are both actually JW TS we'll talk in a little bit more detail about the difference between the ID token and the access token but it's important to know that they are JWT is and then I'm pulling them actually from local storage so if we head over in my machine here to the application tab and then we just take a look in local storage you can see that I have this ID token and this access token and so our view application is actually pulling those from local storage and then we can use the access token for instance to make an off authorized request to our API so what I'd like to do now is to demonstrate that this is a JWT and take a look at what's encoded in this JWT so we have one on the left and one on the right 90 token in an access token let's just take a look at what's in this access token and for this the easiest way is to just head over to JWT i/o and paste this into the encoded text box here you can see it says paste that token here and keep in mind that this is all client-side so we're not actually storing any secrets in this code there's nothing essentially that we wouldn't necessarily want to make public in this code because everything is happening client-side here so what is happening though is that this token has been signed by an authority in this case all 0 and so that if it's tampered with when this token is used to make some authorize a request on our back-end if it's been tampered with we should be able to know because we can verify its signature and so we can see the three parts of our JWT here and gwt's in general are very easy to parse because we can see that the three parts are separated if you will by a period and so we have the header the payload and the signature in the payload we can see that this this particular JWT is in fact a JWT and that the signature or encryption algorithm here is RS 256 and then we can see the key ID here as well the payload has some standard properties including the issuer which is all 0 of course the subject in other words whom the token refers to in these all 0 tokens that are prefixed with our zero and a pipe we can see the audience will take a look at that momentarily the issue that date and the expiry date as well as the authorized party and then the scope is a custom attribute here this is an access token and so we can actually use this when we send this token to the back-end we can inspect the scope to see if this particular user or machine that has sent this JWT with the request has access to only certain things that we want them to have access to if you will in other words that we can use this to basically assign and control permissions and then we have the signature here and if we wanted to we could paste the private key here just to verify the signature okay so that's a quick look at the access token if you were to look at the ID token you'd also find that it's a JWT it has announced in this case in other words the unique value associating the the particular request with the token we don't see the scope attribute here and we'll talk a little bit about the difference between the ID token and the access token in a moment okay so those are our JW T's that are coming from local storage and now that we're logged in we head over to notes now if we request private notes we'll actually be using that access token and now we're actually authorized to make that request and so our API will send back the results that we've actually requested if we sign out note that we can no longer see this information and if we head back to our network tab and refresh here and then request private notes again now we're not authorized to view the private notes if we sign in we now have that access token and we can head over to notes and request them and we have them in fact if you head to your application tab and sign out you can see that when we select sign out our view application is actually just destroying those keys from local storage which is why when we try to fetch them here we've run into this this in which we're handling by saying that we're unauthorized we'll take a look at all that in the code momentarily let's head over to auth0 to look at how we set this up I'm gonna log in to R 0 and then what I've done here is I've created an API so you'll go through and create an API I've called this one PD demo API you're going to get an 8 an ID for the API you'll be able to provide a name and then an identifier here and auth0 will recommend using a URL but this doesn't necessarily need to resolve to an actual URL it's just an identifier it's not something that it's actually going to hit so I've used the URL here but again you don't necessarily need to this is just going to be used as the audience parameter on authorization calls which we'll take a look at in the code momentarily there are some things we can do with the tokens that were issuing we can set their expiration we can choose the signing algorithm will be using RS 256 here and some other things that we can control for the API which we won't get into for the purposes of this demo now if we take a look at the permissions tab here this is a sort of optional thing but I wanted to demonstrate it because it is pretty common you'll most often hear this referred to as scopes and when we looked at that JWT earlier we saw that we had a custom property on it full access this this is a scope and so we can see that we can create scopes here just as key value pairs and then we could use these on our back end in our Express API for instance to determine whether or not there were permissions for the particular requester so we are simply creating one here called full access but again you could use scopes here to control or limit access now if we head into applications we'll run create application and for the purposes of the demo I've created a machine to machine application and I've called this PD demo API app so what you'll get here is a page showing you the domain which you should get when you sign up with off SERO you'll get a client ID a client secret you can provide a description here customize the login page with an application logo and that sort of thing you can choose the endpoint authentication method post is typical here and then we'll need to provide allowed callback URLs in this case we're just running our apps locally so localhost 8080 slash car back will be used and we'll look at how this maps to our front-end application momentarily for allowed web origins and origins cores we're going to just simply use localhost 8080 you can provide a comma separated list here if you needed separate or multiple I should say environments so let's just say you have like dev dot some site and or you know multiple different allowed web origins here if you were going to deploy this application for instance but since again we're running things locally here we'll use localhost 8080 well set an ID token expiration here this is just for that ID token and for the purposes of this demo I also have not set up a refresh token so we can save changes here you can also see there are some Advanced Settings here while zero is really a full-featured platform I'm not associated with them in any way but I have found them to be a really useful platform I should note that grant types here we will be using an implicit flow so we need to select that under advanced settings grant types and check implicit you can see we have WS Federation and our certificates here as well as a list of useful endpoints our JSON web key set endpoint will be important this URL just points to our JSON web key set or jwk s this is a set of keys which contains the public keys used to verify any JWT that's issued by author zero in this case or whatever they are whatever the particular authorization server is so there's JWT s that are issued by auth0 here are signed using RS 256 and our us 256 generates an asymmetric signature which means that a private key must be used to assign the JWT in a different public key must be used to verify the signature so this JSON web key set is just a JSON object that's available at this URL and it it in particular must contain this keys property here in this keys is just an array of those JW KS so you'll have one or more jwk at your URL when you sign in and take a look at this endpoint and this will actually be used by our API and so we'll take a look at that momentarily okay so let's take a brief look at the code and see how all of this gets wired up to allow us to make authorized calls once we've authenticated as a user okay so here I am in Visual Studio code and we have our two projects our client in our server and in this particular demo I'm not going to get into the nuts and bolts of view jeaious in particular but I just want to note that we have a very simple view J's project that was created using the view C alive and then modified in order to support this particular demo so we have an app dot view and it contains this custom navbar component as well as the router view so we have those two different pages in our application the home page and then the the notes page so if we take a look back here and our client got the home page which is just at the root URL and then slash notes takes us here okay so let's take a look at this navbar because this is where things really start to get interesting so within components I've got this nav bar component anything that you see in this component or throughout this project which is prefixed with B flat or B dash here this is provided by a bootstrap view and so these are pre-built components that are provided for us by that library which simply wrap some bootstrap styled components that we can reuse now so I've got a navbar and then the two most important parts of this navbar are the sign-in and the sign out buttons we're only showing the sign-in button if we're not logged in of course and when we are logged in we're only the sign out button we're only showing the sign-in button when we're not logged in and we're only showing the sign out button when we are logged in and when we click on sign in where we're handling that with the handle login method and likewise handle logout when we need to sign out so let's take a look at that these are simple methods which are just wrapping a couple of helper methods that we have in an auth service in the auth service we also have the ability to check whether or not we are logged in so these are essentially proxy methods for that very simple off service that we'll take a look at now let's head into utils and then all service and this is really where all the significant logic happens on the front-end now for the purposes of this demo I have simply defined these constants here directly as strings that are hard-coded but these you would certainly want to put into a config file that you could swap out depending on the environment that you're deploying to you for the purposes of this simple demo just so we can read through it rather quickly I have to find them as constants here but you'll find many of these values over at the off zero platform after you have set up your API and your client application so for instance we need to pull our client ID from our zero and our client domain the redirect we'll look at momentarily we're going to redirect to this application slash callback and then the scope is full access which we looked at previously in the audience again we looked at previously as this PD demo API so pull these values from all 0 directly I'll show you for example where some of them are so client ID we take a look back here we can simply see that client ID here likewise our domain is available here if we take a look at our API we can find our API ID here as well as that audience or identify our value ok so this is really fairly simple to set up because again we are in this case inside of our service just wrapping some functionality by the ethereal library and so we create this new instance this web offense that we pass our client ID and domain and austero really handles most of it from there so for instance when we want to log in we simply call off that authorize pass in this response type string with our redirect URI our audience and our scope our logout method just simply invokes this clear ID token and clear access token if we take a look at those all these are really doing is simply removing from local storage that ID token and the access token and then simply rerouting us to the root URL of our application to get our access token it's really just calling getitem on local storage for those two tokens and then when we want to set those access tokens we'll be doing this in that callback URL route and so we'll take a look at the component that that takes care of this for us but here we are simply calling get parameter by name and we're going to get that directly from the URL and here's a helper function I pulled this directly from some documentation on all 0 and so a zero is gonna come back with these values and then we can simply push them into local storage at whatever key we'd like to refer to them by in this case our access token key and our ID token key we also have a little helper here to determine whether we're logged in so we just get that ID token and then we're simply returning a true or false based on asserting the fact that it exists and that it's not expired and we want to check that it's not expired we can simply call get took an expiration date where we just decode the encoded token and essentially check whether or not it's been expired and then just make sure that we return true or false based on whether or not that expiration date is in the past ok so a very simple auth service now I mentioned we talked about this callback this callback component and this is invoked at the callback route so very briefly let's take a look at our routes and there are only three of them we have a home route a notes route and then the callback route the callback route just maps directly to our callback component so this callback component that we were just looking at this is where I mentioned we would be setting the access token in the ID token and really this is just and then sending us back to that home page and so basically the flow if you think about it here is that we when we click sign-in we authenticate with our 0 all 0 reads our user name and password in this case and says okay this person is authenticated and if they are then they are going to route us back to the appropriate callback route which in our case is mapped to this callback component in view it's going to send us send us back that ID token and the access token in the URL and we're going to parse those using our service using set access token and set ID token and push those into local storage so that we can then use them to make authorized requests so we've authenticated as users our off provider here has confirmed that we are who we say we are when we authenticate and then we can actually make authorized requests to our own API based on the fact that there we have these tokens now in local storage that we can use that have been signed by auth0 ok so how does that happen well let's look in node stat view and we can see another fairly simple view component here again I don't want to get into the details of view too much in this particular this particular video but we have a list of cards that we want to loop through in this case public cards or public notes in this case they're getting pushed in to bootstrap cards and we're just going to display that note value on each of them that come back and then we have a button to get private notes and when we click it we're going to invoke the get private notes method and just below that we loop over for note in private notes and display those to the page in much the same way that we did with our public notes but the difference is in the details of each of the methods so in the methods for this component getting public notes is just calling get public notes from a card service that we'll look at briefly and then it's going to assign the value that it gets back here to the public notes value for this component now get private notes is a little bit different but the functionality is essentially analogous we'll call get private notes and then we assign them to those private notes but in the event that there's some failure we're going to create this toast which is just using bootstrap toast and it's just going to display that unauthorized message for us and then finally it's going to set is loading to false so we set is loading to true which is just a minor sort of UI detail here where we have a bootstrap spinner that's only going to be displayed on our page when we're loading okay so essentially the logic is when we call get private notes show the loader get private notes which makes a call to our note service that will get momentarily and if there's some error in this case we created we create this toast telling us that we're unauthorized otherwise if all is good then we just show those private notes and then no matter what we simply hide that is loading is loading loader once the request is complete so let's take a look at what's happening now in this new service so this is sort of the remaining piece of logic for the front-end and again we should parameterize this but for the purposes of the demo I have a hard-coded constant base URL here this is our API endpoint or API URL base URL and we simply have two functions here get public notes function and get private notes function get public notes is pointing to the route slash API slash public notes we're using Axios to simply get those or make that HTTP request and then return that data and then get private notes however is actually making a request to slash API slash private notes on our API and in this case it's sending along some authorization headers and in this case we need the authorization header prefix bearer and then we call get access token which we looked at previously which is simply going to return the access token from local storage so in the event that we've logged out and we've destroyed that value in local storage then this will be a malformed authorization header because it will just be bearer and then space essentially and so any requests with that header to an authorized route will of course fail which is why it fails when we're logged out however when we log in we hit our callback route which invokes our callback component which sets our access token to local storage or stores it in local storage and then we're able to fetch it from local storage when we invoke get private notes and so now we have an appropriately formatted authorization header with bearer followed by that access token JWT here and when we make this HTTP request now as we look at momentarily our back-end is able to actually use that authorization header to say hey this looks like a signed JWT therefore I will authorize the requester to make this particular request and respond with the appropriate data okay so with that in mind it would be good to take a look at the backend which is really just like the simplest express API with some particular magic provided by with some particular functionality provided by the expression A to B T library and the jwk SRS a library which is actually provided by all 0 so what's important to note here is that we've got two end points again public notes and private notes as we saw invoked from the front end the only difference is that private notes contains this off check middleware and if we take a look at what this is we're essentially invoking this helper method this Express JWT secret to create this secret parameter and so this is what's allowing us to use that RS 256 algorithm we took we took a look at that JSON web key set previously which we mentioned was that set of keys that contains the public keys used to verify any jdb T issued by auth0 in this case and signed using RS 256 so using this express gdb T secret we can generate a secret provider that will provide the right signing key to express JWT based on the key ID in the JWT header so long story short this provides us with some really nice utility here to first of all be able to cache it we can rate limit it and assign a request per minute to to that particular to be KS and we need to provide the the URI here which we pulled from off zero again you can find this if we head back to our application actually and then advanced settings and then endpoints here we can find that JSON web key set URL here otherwise it's always going to be whatever your osteo domain is slash dot well-known /jw KS that json the audience that we need to provide here again is provided to us on our api's page and then if you go into your API this is also what's referred to as your API identifier and then the issuer is just your author your domain and as mentioned we're using RS 256 here so this expression should be T secret is going to take the token that sending essentially decode it and look for that key ID or k ID and we saw that previously in jadibooti i oh it's going to find the right signing key for it which is provided by our JB KS you are a higher JSON web key set and in that and in that way it's going to be able to validate whether or not it is an appropriately sign valid JWT that it can use to make authorized requests and we can just include that as express middleware here on this route and then assuming that it's valid we should be authorized to make request at this route and so as we can see from the demo once we are signed in we have an access token in local storage that we can see here again if you're interested in inspecting it just copy and paste this over into JWT IO and take a look at what's actually encoded in the token but we're actually using this now in Express when we make this particular request to that private notes route or endpoint and in fact if we want to inspect it even further if we head over to the network tab and look at this request that we just made to private notes and take a look at those headers note that we have that authorization header on the request now prefixed with bearer and then this will actually match our access token so if we head home and here I'm gonna select preserve log ed back to notes quest private notes let's pull this up again and then head back home then take a look at private notes in our request headers here we have this bearer and then this token you can actually see that this is in fact using that access token so we're just pulling that from the local storage to make this HTTP request and you can see we're getting a 200 response back from our server so it's essentially taking this this middleware is essentially taking this key it's taking a look at the key ID and then it's using our JSON web key set here to match that up with a key ID here again this is all public and if first of all if a key ID doesn't match any of the keys in our JSON web key set here and error will be thrown but if we do have a match here then it's going to pass the signing key to express JWT and expressed you t WT here will validate the signature of the token the expiration the audience etc and so in this way we've demonstrated how we can wire up a very simple view J s application in which we make a public request to be publicly available around as well as a route that requires authorization after being authenticated with an auth server in this case off the 0 and making those calls to an express Web API alright so that's it thanks for watching I really appreciate it if you guys have any questions whatsoever then be sure to leave them in the comments below and stay tuned for the follow-up video where we'll do a deeper dive on JW TS and topics in authentication authorization in general thanks for watching
Info
Channel: Wes Doyle
Views: 13,070
Rating: 4.8166666 out of 5
Keywords: JWT, Auth0, Vue.js authentication, Express.js Authentication, express.js, learn web development, authenticate api, using jwts, what are jwts, login form, vue login form, express login, express auth middleware, authentication vs authorization, wes doyle, web api authorization, oauth vs jwt
Id: MdDsOp9_mM0
Channel Id: undefined
Length: 32min 44sec (1964 seconds)
Published: Fri May 22 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.