Sign-in Sessions
Dev Agrawal will explore how the session can be a powerful tool in authentication that can unlock security and UX capabilities.
What is a JSON Web Token (JWT) and why do you care? JWTs are a stateless, standardized way to represent user data. This talk will discuss why JWTs matter and the nuts and bolts of JWTs. We’ll also discuss how you might use a JWT in your applications and how to avoid common mistakes.
Dan Moore is head of developer relations for FusionAuth, and currently helps educate developers about auth and OAuth. He’s written, contributed to, or edited 5 books. A former CTO, technical trainer, engineering manager and longtime developer, Dan has been writing software for (checks watch) over 20 years.
Dan Moore 0:12
Alright, so I’m gonna be talking about JSON Web Tokens, as I mentioned, and we will do a little bit of code looking at code later. That’s a sneak peek. But first, real quick about my employer, I am doing this on my employers dime. And I have learned a ton working in Fusion Auth. So I’m just gonna give them a quick pitch. But I promise you this is not a vendorware talk this is about the only time that I mentioned Fusion Auth. So we basically are CIAM, which stands for customer customer identity and access management. We’re very similar to zero. We’re different in that we’re self host double and API first. So basically, we also have a free edition, you can download and run yourself. And people are running it with millions of users and we don’t see a dime as long as you run on your own hardware. If you want us to run it for you. It’s a different story. Anyway, go check out Fusion Auth if you want to. We create a lot of JSON Web Tokens real quick about me. Who cares? You didn’t come here to learn about Dan Moore, you can look me up online. But if you want to learn more, if you have questions, Sean’s going to be gathering those. So I think we’re going to save them to the end. So feel free to type them in the chat, or any other way that you want to get into Scott carrier pigeon, or whatever. And we’ll make sure to look at them at the end of the presentation.
Dan Moore 5:34
Real quick giveaway. I didn’t check with Sean if this would be okay, so I’m kind of just winging this. But there’s an e book called The modern guide to OAuth that I co wrote, It’s our 80 pages of OAuth and OIDC. Goodness. And I’m happy to give that away if it’s in line with CFE devs. Rules. So, if not, then, sorry. So I will, will determine that kind of at the end of the presentation, what I’m gonna talk about.
Dan Moore 6:02
Okay, enough, enough housekeeping, let’s talk about JSON web tokens. I’m gonna talk about JSON web tokens and kind of watch a little bit you need to know about them kind of some of the history, the problems they solve how to validate JSON web tokens, and suddenly we see it’s a little bit problematic is some people don’t do the full level validation, it should. We’ll talk about bearer tokens in general and some of the issues that they have, and how to remediate them. We’ll talk about some common issues that we see with JSON web tokens. And some things that people do that probably shouldn’t. We’re going to then branch out a little bit and talk about refresh tokens, which are related to JSON Web Tokens, but not the same. And then we’ll talk about JSON Web Token revocation. So let’s dive in. So jadibooti stands for JSON web token, if you look at the specifications, it’s actually proud to jot so if you want to be in the in crowd, you can next time someone’s talking about JSON Web Tokens, you can say, let’s look at that JWT and see what how was signed. It’s a standard it’s there’s one of a set of like standards around the RFC 7519. I think 16, 17, 18, 19, 20 are all related. And they’re all about tokens and signing and some encryption, so they’re kind of it’s part of a family of specifications that the IETF did. I think it was about seven years ago. 2015 2016 may have been 2017. But one thing it’s really worth knowing is that JSON Web Tokens, or JWTs, can be either signed or encrypted. So when you’re whenever you’re looking at JSON web token, that’s the candidate first question you’d ask. And the difference between these is that assigned token, you can know the integrity of because it’s basically signed. And we’ll talk a lot more about that. In coming sides, encrypt but the contents of the JSON Web Token are not secret. So you can tell that it hasn’t been changed. But you can’t tell you can’t put it in like, please don’t put in like a social security number or government identification number into a JSON web token that is signed encrypted JSON web tokens. On the other hand, as the name implies, the payload is actually secret, it’s encrypted. I will say that in my years with Fusion auth. And before seeing encrypted JSON Web Tokens, it’s rare enough that I actually tweeted about it, it just doesn’t happen that often. Where sign JSON Web Tokens are pretty much everywhere I’ve seen I see in a lot of places. So I’m going to focus on sign JSON Web Tokens, because that’s just much more common. But just be aware that there are those two things.
Dan Moore 8:48
And the most important takeaway from this point is, if you have a signed JSON web token, and it contains a secret, you need to remedy that right, either turn into encrypted JSON web token, figure out some way to not include that secret. Because anyone who gets a hold of that JSON web token can see that secret. So JSON Web Tokens are often used as stateless, portable tokens of identity. What do we mean by that? What do I mean by that? They’re stateless, because they can be verified as being accurate and not having been tampered with without ever communicating or without, like passing them to a server and saying, Hey, is this JSON web token, okay? Is this job, okay? They’re portable, because they are very friendly to HTTP. They can be put in form parameters. They can be put in headers, they can be stored in cookies. And then when I say tokens of identity, they’re often used at the end of an authentication event. This is certainly how Fusion Auth uses them. And they represent the user. And so then they can get passed to other systems. And the person holding the token can usually be determined to be the person who authenticated there’s some The reason why we use the word usually is there some kind of caveats around that. But that’s how they’re often used. Because of that, they’re great for API’s and micro services, because you can basically generate a JSON Web Token at one place, you can pass it to a client, the client can pass it around, present it to API’s, or microservices and get access to data or functionality on behalf of that user. And the API and micro service can validate that JSON Web Token and know and basically assume that the holder of the JSON web token is the person for whom the functionality should be available. It’s also produced by live identity providers Fusion Auth is not alone in that, right. I know Auth0 does. I know there are other identity providers out there Firebase, I think Cognito does. So it’s a standard. There’s a lot of support out there for that. Right, not just in terms of data providers that I just mentioned. But in terms of documentation in terms of libraries, in terms of understanding of JSON Web Tokens, it’s a lot more prevalent, in part because it’s just been around for a while. And it solves this really neat, really important problem of distributed identity. Speaking of problems, let’s talk about the problem that JSON Web Tokens are designed to solve. So here, we have your traditionally vastly over engineered to do application. So on the left here, we have clients, right? It could be a browser could be a Native Client, it could be something else. And then we have our API’s that those clients communicate with. And then there’s a data store that the various API’s use. The Datastore, for the user API looks pretty typical. We have users, we have roles with a mapping between them. In the to do API, we just have to dues. So this to dues table has some interesting things, right? It has like a text field for the to do a status that we’re going to probably use in a pneumofore. And then we have user ID and user ID. An important thing to note about this is that because we’re in a distributed system, that user ID can’t be a foreign key. So it’s going to be not no, because we’re always going to stuff a user ID in there. But it can’t reference back to the user table that we previously saw. Because you can’t have foreign keys across databases.
Dan Moore 12:34
So in our over engineered to do application, how are we going to access? How are we going to get access to dos? Well, let’s how we obviously are going to start out with do some ham authentication ceremony, right? So we’re going to post consumer user and password, it could be other other means of getting access, we’re gonna post that to the user API. And then let’s see what happens after that. So this is the problem. The problem is how do we tie the to do API, the todos back to the user after that login event. So again, login user API, and that user pay is going to consult the users database. And it’s gonna get back a user and some user data. And, you know, frankly, for JSON Web Tokens for developers, you don’t really care what happens, you don’t care how many times that password is hashed, what algorithm was used anything like that, at the end of the day, you’re getting back a user object, and it’s probably going to be JSON and a modern web application, it could be something else, and that’s gonna get passed to the client. It might look something like this, right? We have a user object, we have an identifier, name, roles, email, other information might be in there as well. Then, because we have user ID 42, and we’re a client, we’re gonna say, hey, I need to get the todos for the user ID 42. I’m gonna pass that identifier back to the to do API, the to do API can go look in the to dues database and say, Oh, Dan has 25 different todos, I’m going to wrap them up as JSON, send it back to the client client gets render them? Is this a good idea?
Dan Moore 14:21
Spoiler alert, it’s actually not a good idea. And the reason for that is that you can’t trust the client, right? You just cannot trust the client. And so someone could see, basically look at what the client, the request the client is making, either via examining the code on the native app, or they could look at the the network traffic, depending on how they wanted to, but they could see that you’re getting it to do with the user ID of 42. And that tells them a couple of things. The first thing it tells them that there’s probably at least 42 users in the system, which is information you might not want to leak. And then second is it lets them iterate over them. Right? So you can start to do have user ID one, get all the to dues of user ID one, and then use ready to use ready three, etc, etc. Obviously, that’s a really bad idea. So we need to do something to the to do API to make sure that it’s not blindly take accepting user ID, the user ID is passed to it, and handing back the two dues for that user, because we need to keep those private. So let’s talk about a couple of different approaches we could take, the first we could do is what I call the opaque token approach. And so in this scenario, what you do is you have the user API generate not just the user data, but they generate like a long random string. And they pass that to the client. And the client is coded to know, hey, don’t present the user ID to the to do API, present the token. Now, the to API gets that token. And it needs to do something with it. It cannot just use that token and look up a token in the to dues. Because you’re still, while you’ve solved the first problem of knowing that there are roughly 42 users or a malicious client knowing they’re roughly 42 users, you haven’t solved the enumeration problem. Because no matter how big that string is, it could be that someone else is going to rent a bunch of a fleet of EC2 instances on AWS, and run through every possible value that token and get spaces skripals to dues. So the gap, I cannot use this opaque token as an identifier in the todos database. What he needs to do instead is present that token to the user API. Now the user API can because it generated that token, it is stored in a database, it can say, Oh, this token is valid. And something I can back to user ID, or just hand back the entire user object. And then that the todo API can can pull off the user ID and then look up the todos. If the todo API presents that token, and the user API says, whoa, guy, Wolf, a wolf person, don’t, this is not a valid token, returns a 401 or whatever other status code it wants to, then the two API knows that someone was fooling around, someone was messing with that token. And that’s either a bug or attempted privilege escalation or something. And the todo API should not return the todos. So this approach is a totally valid approach. You have to like any any, like any engineering issue, there’s trade offs, you have to maintain a user token mapping at the user API, which, depending on number of users could be trivial. It could be a really big problem. It can be very chatty. Because every time that todo API gets a request, it has to present that token to the user API. Unless, of course, it caches some things, which then you’re introducing some other complexities.
Dan Moore 18:03
And basically, basically, kind of a bigger issue from an architectural standpoint is that a couple of these are API that almost everything. So anytime there are requests coming in from any API’s that are related to a user, you need to extract that token and present it to the user API. That’s fine. If you have two API’s or three API’s, if you end up having a large number of API’s, you end up having to scale up the user API significantly. One thing that’s worth noting is this, this kind of flow is OAuth introspection. So this is an IETF, blessed RFC. There’s the number up there if you want to read it. So totally valid pattern for determining the validity of a client request, basically. I should say it’s actually not exactly OAuth introspection. It’s very similar to it, because, well, no, I’m wrong. Actually, it is exactly what with introspection.
Dan Moore 19:00
So JWTs are an alternative solution to the problem that we’ve just illustrated. So with a JWT these are API generates a jot similar to the way it generated an opaque token, and then passes down the information to the client. And then the client can extract that JWT and present it to the todo API. The nice thing about this is the todo API can now look at that JWT and determine who signed it when it was good for who it was for and other attributes without ever talking to the user API. So a JWT can be signed with a public private key pair or a symmetric key. We’ll talk a little bit more about that difference in the future in the in future slides. But this is the big one, right? The second point, the todo API never had to talk to the user API, because the token has been correctly signed. Another win is that a JWT can contain a lot of other information. It doesn’t have to just be kind of a binary yes or no or just a user ID, it can contain roles. It can contain stats about a subscription, you know, plan information, whatever else you might want to have about a user, again, with the caveat that anyone who gets their hands on that can see the contents. So you might not want to put anything that’s secret in there about the user.
Dan Moore 20:35
So let’s take a look at actually what a JWT looks like. So enough boxes, here, we have a signed JSON Web Token has three parts, it has the green part, which is the header, the blue part, which is the body of the payload, and then, excuse me, the white or tan part, which is the signature. The header and the payload both are basically basically for URL encoded strings. That’s why you’ll recognize whenever you see EYJ zero, that is the kind of start that’s basically for your URL encoded as J zero, have a curly brace might be just the UI, actually. But anyway, so you can decode these, if you just Google for base64 decoder, that’s going to work most of the time. I think your URL encoding changes a few things. But this is a header right now. And this basically has information about the JWT that’s metadata. So this is the algorithm that was used to sign it, the type of the JSON Web Token because you have multiple different types. Sometimes there’s a key identifier in there to determine which key was used to sign up. The body is where things get interesting. And so as I mentioned earlier, you can put whatever you want in a JSON Web Token. It’s just a JavaScript or it’s a JSON object. So the key is the JSON object, because identity geeks like to use jargon are called claims, their claims about the user. And some of these claims, some of these keys are standardized and others are not. issuer is, okay. issuer standard exprtation, EXP standard audiences standard AUD sub is standardized, but the last two are not.
Speaker 2 22:27
Name is not standardized, and roles is definitely not. And you can basically put whatever other objects you want that might be helpful to your downstream job consumer, right, to the todo API. One other thing worth noting here is that the roles show that it’s not just primitive values that you can store in a JWT, you can store arrays, you can store arrays of arrays, you can store arrays of objects of arrays, whenever you want. One question that often gets asked, when I give this talk is, how long can a job be? And the answer is, there’s no limit on the Java, there is a limit on the transport layer. So if you’re passing a JWT around has a header. And there’s a there’s a length that some browsers impose on a header, that limit is the limit of the Jot, right, if you’re passing around as a cookie, then you’re gonna be limited by the size of a cookie unless you take steps to kind of like break it apart and put it back together again.
Dan Moore 23:27
Finally, there’s the signature. And the signature is a really, really important part of a JWT, chances are very high that you’re going to just use a library to generate the signature, but it’s worth understanding kind of what it does. Basically, you take the header and the body or the payload, and you run a cryptographic operation over it. And then you basically for your own code, the output. And the particular kind of operation there is depending on what algorithm you use, again, symmetric algorithms are different than asymmetric algorithms. But chances are, again, you’re going to use a library to do this. But it’s important to know that because you run this cryptographic cryptographic operation over the header in the body, which is specified in excruciating detail by RFC 7519, then that that signature will be tied to the header in the body. And if anyone tweaks the header in the body, or the body, right to give themselves a different role, for example, then the signature will no longer match. Which leads us to JSON Web Token validation is the things that you need to do as a developer when you receive a job. So again, this is the to do API or any of the other API’s that you might write that take that JSON web token from the client, and are protecting I mean, remember, the two API is protecting my precious precious todos of like going to the store to get milk and making sure I walked the dog. I want to make sure that only I can see the goes to dues. And so we need to make sure that we validate this JSON web token to make sure that it is tied to the correct user. So first you need to do is validate the signature. And my advice here is just simply use a library, I have not seen any major languages, programming languages that don’t have a some kind of JSON Web Token library, preferably an open source one to be totally frank. If you reuse library, and you provide it with the needed parameters for a to check the JSON web token, and it gives you any kind of exception or error or says, Hey, this signature doesn’t match stop, you can stop processing because something’s gone awry. Again, either a bug or privilege escalation or something else going on. But the JWT you have presented is not the JWT that you should, is not a valid JWT for you to keep moving forward with with whatever the API call was.
Dan Moore 26:01
The next thing, excuse me, and this is where I have found that some people don’t fully do this is you need to validate the claims, you need to validate the values of the keys have that JSON object that come in after the signature has been checked. This is business logic, to some extent, right. There are some libraries to help you with some of the claims. But if I need to make sure that only the people who the only people have access to my todo app are the people who’ve paid I might put a claim in the JSON web token that says you know, paid user of true if they’ve logged in there, they are paid. That’s business logic to know what attribute I’m looking for in the todo API. So that means you need to write it, that doesn’t mean that you need to write it for each individual API, it’s possible you could make it into like a custom library or, or module or something like that. But you’re gonna have to write this logic.
Dan Moore 26:59
So here’s our payload. We have an issuer, we have expiration time, what are the things you need to check? Well, as I mentioned, some things are standardized, and some things are not. Here, we need to check the issuer to make sure that this job was created by the person or thing that I thought created, right. So that’s, again, my user API in this scenario. So that means that we want to make sure that the two API knows who generated this JSON web token, we also need to check the expiration time. And this is the number of seconds since the Unix epoch. And if this is in the future, your job is most likely valid. If it’s in the past, your JWT is not valid, and you should just stop going forward. It’s just the same as if the signature validation failed. The audience claim is another thing you should check in this is who the JWT was created for. So in this scenario, the to API is the thing that the JWT was created for. And so if you get an audience claim, that is not what you expect, you should stop processing. Why is this an issue? Well, it’s possible that you might have multiple different API’s that are being called, and different user roles for each one. And so if someone’s an admin in the to do API that might get grant them, you know, access to like, seeing other people’s to dues. If they’re an admin, the county API may give them the ability to like send out a check. So you don’t want a JWT that’s created for the to do API to be presented for the to the county API, and give escalated access.
Dan Moore 28:55
Let’s look at a little bit of validation code. So here is and this is there’s a link to it at the end of the presentation. This is some JavaScript code that presents kind of a simple validation scenario. So we have lines three through 17. We’re pretending is the user API, right? So it’s going to do some other things and log people in, you know, login assumed. But we’ve assumed we’ve already authenticated the user to some extent. Now we’re just creating a JSON web token. And we’re signing it. So we are asking you a couple of different claims. And we are on line nine, making sure that it is good for five minutes. And then we’re going to print it out to the console. Again, in the real world, you’d send this down as a cookie. Typically, there are other options as well. And then lines 19 on we’re actually pretending we’re the to do API right where we’ve received this token. And now we need to process it. And so the first thing we do is we, this particular library, lets me check the expiration time in the issuer. And so that’s what I’m doing on lines. 21, I’m basically just setting up the library on line 27, I’m having it verify the signature, and it will last. So do that additional verification around expiration time and issuer. And then lines 29 through 34 Are my business logic, right, I’m checking the audience claim I’m checking that there’s a premium user value. And I’m gonna throw exceptions. If that’s not the case, in the real world, you’d want to again, send a 401 or, or some other kind of more sent more sanitized version of the problem. But this is demo code. And then line 38, I’m going to pronounce the the verified object. So let’s go ahead and run it real quick.
Dan Moore 31:08
See, I get this JSON web token, UI, J H. So yeah, UI is the base URL encoded curly brace, I get this and then this translates back to, in my to do API, I can see that I have all this information. If I do this, again, I get a different, same header, different payload different signature. Because the time has changed. If I change, let’s just change the change the HMAC key. So we’re going to do this, we’re going to do const to each one a key. So this is where the signatures don’t match. Or this is a way to show what happens when the signatures don’t match. Because some nefarious person is creating a JSON token using this library. And they think they found the signature. But this is the real signature that has been distributed through my secrets management system. completely invalid signature. So that’s exactly what I want to have happen, right? Because the fact that that signatures don’t match means that I can’t trust the integrity of the job, which means I can’t trust the integrity of the user. And therefore I shouldn’t give them any access.
Dan Moore 32:35
So there’s a bunch of other examples here. I haven’t touched him for a while. But you can see you can do with like, you can see HMACs in in kind of various different ways. And like I said, I have some other examples in different languages, but that’s the JavaScript example I have. So let’s look at bearer tokens, right. So we’ve kind of seen why you might want to JSON Web Token. from an architectural standpoint, we’ve seen kind of the nuts and bolts in this skeleton of a JSON Web Token. We’ve looked at validating JSON web tokens. Let’s talk about bearer tokens general so bearer tokens are, it’s a bigger thing than JSON Web Tokens, then jots they tend jots tend to be used as bearer tokens. But you could have a bearer token without it being a jot. The whole idea of a bearer token is that you have a it’s something for which the possession of the item is proof that you have access. That’s a bit of a mouthful. So the way I always think of it as analogy is that a car key, lets you have a fancy shmancy car key with a biometric sensor. If someone holds the car key they have access to the car can drive the car. So that means that you need to be careful with the key. Because if you leave the key in the car next to the car, someone else, your neighbor, someone walking down the street can pick up the key and get in your car and drive off with the car and you know, get access to that valuable functionality of being driven around in your fancy schmancy car. So, in the world of jots, what that means is you need to protect the JWT that is issued by the user API, because if a bad actor gets the HWT as they do here, they can present that to the todo API. And the todo API will say, Oh, cool. This is a valid JWT, because the bad actor didn’t create a new JWT. They just stole an existing JWT, right? So the todo API, I’ll say that’s valid JWT, and I’m gonna hand back those todos, just as if Dan himself had handed me that JWT. So that means that when you store the token, and also when you ship it around, you need to be careful about what you do with it. So as far as token, so is like, securing security token and transit https is kind of the gold standard. If HTTPS is ever found to have holes in it, we’re gonna have a whole lot of problems. But definitely, you know, and also don’t put it in you don’t put JWTs that are sensitive in URLs. Because you are always get cached as, as a query parameter.
Dan Moore 35:26
Anyway. So token storage, basically recommend server side storage, typically, it does depend because your use case could vary. We also recognize that sometimes you want to send it down to the client, if you’re using a browser as a client, you want to make sure that you store it as HTTP only secure cookie, that removes a whole class of cross site scripting issues. Whereas if you store it in local storage, then any JavaScript on your page can access that access token and send it off to a server in country X, Y, Z. And then that server can make requests based, basically, masquerading as the user. Right? That’s one of the main threat vectors with with JSON web tokens. If you have a Native Client Server Browser, then you’re going to want to use like a secure storage option, like the keychain, or I think Android has something called secure storage. So you just want to make sure that people like other malicious software, either executing the browser or execute on a near device don’t have access, easy access to this access token. So let’s talk about some common issues that we’ve seen with JSON Web Token and implementation thereof. So first, I’m gonna keep hammering home, you have to validate the JSON web token, you can’t just look at the signature, you have to validate a signature, you have to check your claims, both the standard ones and the custom ones that are business logic. So please do that. You also want to make sure you don’t put a secret in a JSON Web Token. Again, it’s basically for your URL encoded JSON. The integrity is guaranteed and not secrecy. Again, this is more for the signed JSON Web Tokens, encrypted JSON Web Tokens are a different ballgame. Again, not super common, so I’m not going to address them.
Dan Moore 37:25
The other thing that’s maybe also of interest is that you can leak information from a JSON web token, even if you don’t put any secrets in there. What do I mean by that? Well, you may have noticed that the audience claim of the payload we looked at was not a number, it was a quid, it was a UID. That’s because if you put in a number, then suddenly an attacker knows something, right? Because there’s no secrets in a in a JWT. So if you put 42 for the audience ID or for the subject claim, which is basically user ID, then suddenly, people know, well, there’s at least 42 users probably. And so therefore, just want to make sure that you’re aware that a JWT can definitely leak information. If you use symmetric key signing, which is the HMACs signing, which is what I showed here, in the code, that’s where the secret is shared between the persons, the entity signing the JWT, and the entity verifying it. But because the way it’s built, you can actually brute force that and find the secret. With nothing more than the JSON web token, basically, you just like, redo that cryptographic algorithm time and time again, and see whether the signature matches the operation with with a given secret, right, like you try secret A, and you run the operation over the header of the body and you see the signature matches, then you try secret B secret, see yada, yada yada.
Dan Moore 39:04
There’s a little GitHub project right here, which does this in C. If you know, you use HMAC key of length four, it’s going to solve it in like 30 seconds. If you have a HMAC with length of, you know, 100, it’s gonna take a lot longer, you’re probably going to hit Ctrl C before that ends. You don’t want to use the none algorithm. So we talked a little bit about the signing algorithms in the header metadata. But the none algorithm basically says, Hey, I don’t want any signature on this JSON Web Token. That means that there’s no integrity check, which basically means that anybody who wants to who discovers your API that accepts this job with no algorithm, with no signature can basically create whatever payload they want, basically, for encode it and present it to your API. This is a totally valid JSON web token. So You can think of this as like unsanitized credentials, right? We’ve always been told don’t accept unsanitized user input. But this is even worse. This is unsanitized. Hey, this is who I am. So don’t just don’t ever accept it on our them. I was talking about asymmetric key pairs versus symmetric key pairs a little bit. So we have here, a JSON web token that’s generated for the from the user API, it’s past the client client presented the to API. As I mentioned before, one common common algorithm is called HMAC.. And that means that the user API and the todo API share a secret. And the user API uses to sign it, that API uses it to verify it, you have to have
Dan Moore 40:50
some way of distributing that secrets securely, some way of rotating that secret. And you also have to secure the geo API in this situation. So when you do is, you know, just distributed deployment time, maybe you distribute 10 secrets, so you have some kind of rotation capability. But a symmetric key pairs avoid this kind of deployment complexity. And with asymmetric key pairs, the private key, this is like RSA, or elliptic curve cryptography, the private key signs, the Jot, and the public key verifies it. So this is helpful for a couple of reasons. One, it lets you scale out situations a lot more. You can imagine sharing a secret between, you know, a small dev team that’s maintained two or three API’s not a big deal. On the other hand, if you have two different companies or two different departments, then sharing your secret becomes a much bigger deal. So in this situation, we have Pied Piper that owns the user API. And then Hooli owns the zoo API. And basically, the user API generates the JWT signs up with that private key, and then passes it to the client, the client presents it to the API, which can get the public key, because the public key is public, and then verifies the job. That means that this can scale out to adding in, you know, other organizations, including ones from different movies or different TV shows. The other reason why this matters is security. I kind of alluded to this, but the the thing that is used, if you’re using a symmetric key pair, that thing that is used to sign this job is the same as used to verify that, that jot at the zoo API, that means that suddenly, your attack surface is much bigger, because you have to make sure that everybody that is verifying a jot is secured the same extent that the user API is secured, because if anybody steals that secret, then they can sign jots that are indistinguishable from those that are signed by the user API. So again, that means that if someone steals that secret, until you until that shared secret is rotated, they can sign JWTs, giving them whatever axisaccessthey want. Or they can create their own custom payload, observing your API traffic and give themselves super admin access, or whatever else they can get access to.
Dan Moore 43:19
So you might say, Well, Dan, why would you ever use symmetric key signing? Right? It seems like the security implications of nothing else are a good reason to not be main reason is that slower, and it’s more complicated to understand that that’s a big reason, like I did some benchmarks, it’s been a year or so you’re two, but the asymmetric key pair was between three and 10 times slower. So if you’re processing large JSON web tokens that trade off, maybe worth the deployment hassle. To share public keys, you have a couple options, you can use a standard or you can distribute the keys. Basically, the todo API here, if you’re using an asymmetric key pair, the todo API needs a public key, you can distributed as part of the deployment artifact again, you can put 10, or 20 different public keys in there. It’s different than distributing the shared secret because if someone steals a public key they break into the gap is still the public key. No one cares, public key is public. But a more common situation is for you to use the todo API to request a well known endpoint. This is another standard. This basically is a list of keys. And there’s a lot going on here. The important bits are right here the algorithm was of the key, the key identifier and then the actual public key, which starts with MII, and this key identifier which starts with UK zero matches the key identifier in a JSON Web Token very Typically, so you you’re as you’re processing this, this request at the do API, you’re going to look and see. And again, some of this will be handled by a library. But you’ll need to look and see what the key identifier is. And that’s going to tell you which public key to use to verify the job assigned by the corresponding private key refresh tokens. And I know I’m running out of time, so I want to make sure I have definitely time for questions. So I might move through this a little bit quicker. But refresh tokens are basically just because JWTs, especially when users access tokens are meant to be short lived, like seconds or minutes, refresh tokens can be long lived, and refresh tokens are basically presented to the user API, to present the user API to create new JSON web tokens. So they exist because if you imagine a world without refresh tokens, then you have pretty to two pretty on appealing options. The first is when an access token is short, right? If you follow recommendations, and you keep your access tokens, or jots, to have a lifetime of like five minutes, then anytime that access token expires, suddenly the user has to log in again, which I don’t know about you. But I probably wouldn’t use a service that made me log in every five minutes. The other option is you say, Screw it, I’m gonna have my JWT be good for a month. That means that, yes, the user didn’t have to log in regularly. But like if someone steals that JSON web token, anyway, they have like a full month to like, or they have a long time to like, pull down the data to probe to use that JSON web token. So the way refresh token works is that you actually request it when you start the authentication process. And then it’s sent down along with the JSON web token.
Dan Moore 46:55
And, again, the JSON web token is presented to the to do API. And then there’s data sent back, right. So and this, this kind of pattern happens. For the lifetime a JSON web token, eventually, this and we’ll talk them will expire. And the to API will say, hey, hold your horses note, you don’t get any more access to my to dues, the client can catch that. And then they can present the refresh token up to the user API, these your API can say, oh, yeah, this, this user hasn’t logged out, this user is still valid, this users pay their bill, I’m going to issue a new JSON web token. And this orange JSON web token is sent down to the client, the client then can present the JSON web token to the to do API, which can then validate again, it’s good for another five minutes, yada, yada. So we basically re authenticate the user in a silent manner. As far as log out in a JSON Web Token basis, in a JWT based system, you’re pretty much limited to revoking the refresh token. How that works is the client, when the user clicks the logout button, they fire off a message, the user API saying, Hey, don’t issue any more JWTs for this given refresh token. And then they delete them from their digital, the client then deletes them from their storage. JSON, actually, revoking the JWT itself is a different ballgame. And the answer we get when people say, Hey, can you revoke JSON web tokens? It’s kind of you can’t really, there are, there is a RFC out there. 7009, which allows you to revoke a refresh token. But if you use that particular specification, then you basically lose the ability to I won’t put this carefully, you basically have to check back in with the user API. So you’re begging basically back in the opaque token world with maybe a little more standards based and more flexible token, but that’s really not it. Another option is you can rotate the keys. And that would work. If you had like a huge break, like I think, GitHub a couple of years ago, or maybe a couple of months, you’ll log everybody out. And I don’t know if that was a some kind of security thing or what was but like that, essentially, I read that as they rotated their keys, because one, maybe one of the keys have been compromised or something like that. I don’t know. I shouldn’t say that about GitHub. I don’t know the details of it. But if you rotate the signing key, then when the when the public key is retrieved. It won’t match, right? Because if you remove the public key, imagine a job was signed by public key A, then you later remove that public key A from your list of public keys. Now it’s not gonna be able to the library is not gonna be able to find the valid public key. And so the signature check will always fail. Another option is to have really short lifetimes, you know, we’ve seen people who have lifetimes of seconds, which basically makes the job like a one off thing. A third is that denialist. And the way this works, and this is fusion OS specific, but I’ve definitely seen it implemented in other libraries and other situations. Basically, when someone logs out, we fire off an event. And that gets sent to a bunch of different API’s this this, and it says this refresh token has been revoked, okay.
Dan Moore 50:41
And then, you know, make note of this. And then the todo API stores that information and says, Okay, this user now has, basically logged out. So if I see an access token is tied to this user, I should refuse to give any data for that particular user at that time. Some alternatives, you know, you can use web sessions, I think jots pair nicely with those in terms of server side storage, web sessions have their own kind of costs and benefits. You use cookies, it’s less scalable, a lot of ways you kind of have everything running through a central area. And but it is simpler to understand. So in conclusion, you know, I think JWTs are a great tool to have in your architectural tool belt. They are not a panacea. They have trade offs, and strengths and weaknesses, like any other solution. So some additional information. We have a JWTjob debugger, we have that sample code I mentioned, I have a couple of different articles if you want to read a couple 1000 words on JSON web tokens. And there’s another pitch for the future of communication, which is, again, a free authentication authorization server. If you have any questions, I’m happy to take them at this time.
Sean C Davis 52:04
All right. Thanks, Dan. That was That was great. I feel like I learned so much there. And I have a ton of questions. First one here. Can you go back? I’m just sharing your screen just for a moment. Can you go back a slide? And we had someone who was looking with the one with all the links
Dan Moore 52:25
Yeah, of course. Yeah.
Sean C Davis 52:27
All right. Just just gonna keep this up for a moment here. Someone had some questions about the usage. And I felt like your your code example, kind of nailed that. So I’ll leave these up for just a sec here. While it asked the other audience question, which was just just to clarify here. So it came in a little bit earlier in the presentation and was asking if the key needed to be shared that the secret key needed to be shared among all of the different services that you’re using on the server side. And what I got from that was, it sounded like yes, but that’s a challenging problem to solve, especially if you have larger teams, so that you’re recommending, usually if you have multiple services, you would look to implement the asymmetrical key pattern.
Dan Moore 53:14
Yeah, I think that’s a fair statement. I think that when you get started with JSON web tokens, and you’re playing around with them, it’s so much simpler to understand a shared key. But the question asker nailed it, right, like it is, any kind of shared secret between different services gets a lot harder when you have more and more services. So in that scenario, I would say move to an asymmetric key.
Sean C Davis 53:42
Okay, okay. That makes sense. All right. And I had, I had a couple questions here myself, one was, so you mentioned a few times the difference between sign tokens and encrypted tokens. And it’s, it was interesting to me, because it sounded like there. There, you had to be more cautious using a signed token, but they’re also much more popular. Do you have a sense of why why if encrypted tokens are more secure, why aren’t people using them more?
Dan Moore 54:15
Sure. I would think that the there so this is just based on anecdotal, right? I don’t have any good. I haven’t had like a deep discussion with anybody. But I think that sign tokens are easier to implement. I think they’re faster to process. I think that you don’t when you when you have a signed token, you’re kind of not worried about how people get the key to decrypt the encrypted content. So Okay, those are kind of the pieces that I would think of.
Sean C Davis 54:54
It makes sense makes sense. are there instances where a JWT would not be a good choice. I mean, you know, you said there’s trade offs. Are there it can you think of an example where you like, Yes, I definitely wouldn’t use it in this case.
Dan Moore 55:09
Sure. I mean, so. So. Yeah, I think an example that is kind of close to the this presentation is that through API, right, like, I think that the do API could just use a API key, right. And if you didn’t need key rotation, or other things like that, and it was pretty simple API, a simple string that doesn’t have any other information, it is kind of going to be enough to kind of indicate that the user is or the client is who they say they are, right, if it’s an internal app or something like that. That’s an example. I think, it’s another example of where jots would not be a good fit. I think if you need to store something in local storage for whatever reason, or you can’t find a secure location, then you want to like look at a different class of solutions that tie the token, whether it’s a job or not, to a to the client more tightly. And an example that there’s a couple of standards people can look at One’s called Depop, which is actually moving through is about to be an RFC. The other is called MTLS. And those, right, and remember, I use the analogy of like a car key, right? Like Depop and MTLS are a way to like, actually create a biometric car key, where it is tied to the client, and the client owns something that it presents to the server in addition to the token, and so you can be absolutely 100% positive that it is that client, not some server in country XYZ.
Sean C Davis 57:04
Gotcha. Okay. But until then, it sounds like it’s a bit more identity based, if you just need basic information from an API is some sort of service key is probably good enough in a lot of cases.
Dan Moore 57:17
I mean, it depends on with depends on like, how big the team is, and whether you have other infrastructure setup that already leverages jots. But yeah, I mean, certainly I’ve written API’s where it was just like a key in a database, right? Or Nike, it was an API key that was a field the database, and that’s perfectly fine way way to go. The joke I always say is like, well, then you start your security team comes in and they want well, we need key rotation. And then you’re like, oh, and we refresh tokens, oh, or some way to refresh this API key. And then we need more information than we have in just a string, we need to encode a JSON object. And then you’re like, congrats, you’ve just reinvented OAuth. So, you know, but again, if I was like a two person startup, or a five person startup, I was just trying to get stuff shipped. I would definitely look long and hard to just plain API keys.
Sean C Davis 58:12
Okay, okay. And so you talked a little bit also about storage methods for the token on the client, and said that you generally lean towards a using cookies and secure cookies, is there a scenario where you might, whether it’s a local storage or whatever, that you, you have a preference for another approach?
Dan Moore 58:36
Yeah, so you just this really comes down to your threat model, right? Like if you are using jots, mostly for protecting API’s that are kind of public ish anyway, and you’re just using it to like track stuff and make sure they’re not abused, then you could constantly put it in local storage, if you. But I mean, if you audit all of your JavaScript, and you’re 100% positive, that there’s no possibility of some malicious JavaScript getting into your page, maybe your local searches, okay. I know amplify, for example, uses local storage, I think it’s a pretty common pattern. With a lot of client side JavaScript libraries, that were cookies fall down where cookies fail, is that the cookie gets sent along to any requests on the same domain. Right. So if I set a cookie to have a domain of example.com, and my API is an example.com, and I have another API to do API to.example.com. Then I get because of browser semantics, I get like the cookie, the access tokens get passed around for for free, right with no effort on my part. But if I want to make a call to, you know, to do.com something that cookie doesn’t get passed. So that’s where this is a really great pattern for kind of an enterprise II kind of thing or something where you control both both sides. of the of the scenario. But if you are running a browser app, and you need to call Google’s API’s and somebody else’s API’s and somebody else’s API’s, we’re not gonna be able to set a cookie to, to match all those domains. So the alternative there that we recommend is a proxy. But I think that is where the local storage comes from is because it’s very easy for a JavaScript client to pull the value out of local storage and put it into header and make a fetch call against as long as course is set up against any any domain. The flip side, of course, is that it’s possible for malicious JavaScript to look in local storage and see there’s a juicy access token and again, ship it off and use it for other purposes. So where, you know, my recommendation is always cookies, and then server side if cookies don’t work for the browser scenario, but I understand you know, people have different threat models. And so if you’re not bummed by somebody getting an access token, or you think you’ve locked down JavaScript enough to the browser enough that there’s no way that like, the marketing person is going to put in a CDN, you know, a script for some third party SAS, and that third party, SAS is gonna use NPM. And NPM is gonna like have a left pad issue or something like that. Like, if you have things locked down enough, maybe local storage is okay.
Sean C Davis 1:01:23
Okay, okay. Great. I love that. All right, we’ll end the session on one last audience question. This is from Martin and say, I’m not under, I’m not sure I understand why the long lived refresh token is better than a long lived. On loop refresh token is better than a long lived refresh token, if a malicious user gets ahold of a refresh token, doesn’t that just give them the ability to request a job and get the same access as they would have? If they had the original job?
Dan Moore 1:01:54
It’s great question. So the answer is that because the refresh tokens go against the user API, we know a little bit more. So we can do things like watch to see if a refresh token is used twice. We can do things like see where a refresh token request is coming from, and build little more intelligent intelligence into that. In OAuth 2.1, which is the next generation of OAuth, which has been moving through the RFC process for a couple of years, they actually recommend that all all refresh tokens are either one time use, or they are bound the client cryptographically. So that’s that was kind of their answer is you can make refresh tokens more secure, because you’re building in the security in one place and the user API rather than having it be the responsibility the to API and the reminder API and all the other API’s, you can make it more secure. But that’s a great question. Because it is, you know, a common question of like, well, doesn’t the refresh token, give me the keys to the kingdom? And I guess my answer, if someone really pushed me, that would be like, Hey, if you’re really worried about someone stealing the refresh token from the client, put it all server side, right? And is use web sessions, and then you have to deal with session writing, but like, you don’t have to deal with anything else.
Sean C Davis 1:03:13
Right, exactly. It seems like if you’re going to take this pattern, that it’s I mean, you have to you have to figure out where’s your line where you’re, you’re comfortable with the risk? Because you’re not, you’d never have zero risk, essentially, right?
Dan Moore 1:03:28
You can’t trust clients, right? I mean, that’s the end of the day, I hope all your all the audience knows that. Anybody. Anytime you’re, you’re I actually worked at a startup a couple of years ago, many years ago, actually, now that was trying to like encrypt Java scripts, right? So that it could not be like, tampered with or modified. And you just can’t do that at the end of the end of the day, because the runtime needs to be able to reheat and run the JavaScript. You just you’re always going to have an attack vector from the client. So if you’re really, really worried about access tokens or refresh tokens being misused, then you got to put them on the server.
Sean C Davis 1:04:11
Great, yeah. Well, I feel like that’s a that’s a great way to end and I really appreciate your time.
Dev Agrawal will explore how the session can be a powerful tool in authentication that can unlock security and UX capabilities.
Vinicius Campitelli will show us options for building passwordless authentication into your applications and how to get started.
Alex Patterson will show how you can wrap existing REST APIs in GraphQL to give you the benefits of GraphQL without requiring a major rewrite of existing REST APIs.
TheJam.dev is a 2-day virtual conference focused on how to build modern web applications using Jamstack, serverless and more
TheJam.dev is a 2-day virtual conference focused on building modern web applications using full stack JavaScript, static site generators, serverless and more.