 Hello everyone and thanks for joining. We are live now and I am excited to get started. My name is Aaron Parecki and I am excited to talk to you today about protecting your APIs with OAuth. We've got a full agenda today and going to pack a lot of information into this next hour. So a little bit of housekeeping. Hopefully you're familiar, you familiarized yourself with the window here, the chat window interface here. I am keeping an eye on the Q&A window. So if you do have a question, please use the Q&A window to ask it there and I will be keeping eye on those questions and answering them as we go. If I don't answer right away, it's because I'm probably saving the question for later or I'll answer it one on one privately back in the chat window. So let's get going. The schedule today, we've got a lot of information to cover. I'm going to start by talking about a little bit about some background on OAuth before we get into the API side of things. And that's to kind of set the stage and set the context for the rest of this discussion. So a little background on myself. If you haven't met me yet before, I'm Aaron Perrecchi. I'm a senior security architect at Okta. I'm also involved in the OAuth standards group itself where the spec is developed. And I've been working on, you know, with the group on several of these latest developments in the space and working on specifically a spec around browser-based app security in OAuth. I also maintain the website OAuth.net, which is the community website of OAuth. And there's a lot of good links on there out to further other resources, good blog posts and tutorials and things like that. So I want to start out by saying, if you've ever tried to read the spec, this is the OAuth 2 spec. And if you ever tried to read it, I apologize because it turns out that specs are actually not good tutorials. They are written more like a legal contract. You know, every word is very carefully chosen. And every word is defined in like five other specs. And I think part of the one of the worst things about OAuth is that it's not even just one. It's actually like over a dozen different specs. And some of them are developed in different groups. And, you know, it's it can feel overwhelming to try to actually understand what's going on and how to actually navigate this space. So I want to spend a little bit of time to get around speed on the sort of basics around how we actually start OAuth, how we got here, and why we even have this in the first place. So this was actually a very common pattern on the internet a long time ago. And we don't see it too much anymore. It's only only a few places are still doing this kind of thing. But, you know, this was a common pattern where you would sign up for some new app like Yelp, and it would ask you to enter your email address and the password to your email. And you're probably thinking like, why would I ever give my email address account, let some random app log into it, right? Well, it turns out that it wasn't just like small apps like Yelp, it's even Facebook who was doing this, right? And people have been, you know, we're happy to go and do this, and give these applications their passwords, because they actually wanted the end result of what the app was promising, which is that it was promising to find their friends on this network by reading their address book. So, you know, this quickly, we became apparent that this was a problem and a bad pattern to follow for building applications. And we needed some solution where this application can access the contacts on your account, but doesn't have the ability to access your actual email. So, that was the original problem that OAS had to solve, was how can we let an app access my data without giving it my password? So, this takes a lot of different forms, right? You have like Yelp trying to access your contacts from Google, you have Last FM trying to pull your listening data from Spotify, you've got Buffer trying to post tweets, and the thing that all these have in common is that it's this application by this one company trying to access data in an API made by a different company. It was always about third-party access to accounts. And that was really how Oauth was created, was to solve that specific problem. And, you know, over the over the years, it turns out that Oauth is actually useful for a lot more things, and we're seeing it deployed much more widely than just for third-party app access. And what's particularly unique about Oauth and sort of why this space ends up being pretty confusing is because in Oauth, there's actually no guarantee that an access token that the application gets says anything about a user. So, I like to use this analogy of checking into a hotel. So, when you go to a hotel and you go to the front desk, you give the person at the front desk your ID and a credit card and they give you back a hotel key. You take this key and you go to the door of your room and you swipe the key and the door lets you in, right? So, this is actually, it turns out, exactly analogous to Oauth. And the person at the front desk is the authorization server, the key card is the access token, and the door is the API. And what's interesting about this is that in order for this system to work, the door does not actually need to know about the user. The door does not need to know your name or even your email address or even a unique ID for you. It just needs to know, does this card have access to this door right now? And that is exactly analogous to an access token in Oauth, where it is technically possible that an access token doesn't even represent a user. And of course, there's plenty of times where, you know, the access token does represent a user. And in order to do that, we have to add something else and sort of add things into Oauth because it doesn't provide that out of the box. So, in Oauth terminology, we actually say that, you know, applications use an Oauth flow to get an access token. And then which flow they use will depend on what kind of app it is, things like where it's deployed and other properties about the apps. And we won't go too much into that. I normally cover that in a different session where we talk, where we focus on Oauth clients. But I do want to talk about the most common one, the authorization code flow. And that is for web apps as well as native apps. There's also the device flow when your app is running on a device that doesn't have a browser. There's also password grant, which is not really Oauth and it's kind of getting deprecated soon anyway. There's also client credentials when there's no user involved. So, the authorization code flow is the most common one. But the thing about these flows is that at the end of the day, they all result in the same thing, which is that the application has obtained an access token. And the access token will just be a string. As far as the app is concerned, it's just a string. It's going to go put that string into a HTTP request, make a request to some API, and hopefully the API will then do the thing it's trying to do. So, I'm going to quickly go over the authorization code flow and talk about how an app can get an access token in the most common way. And then we're going to talk about diving in to access tokens and actually parsing information out of them and understanding more about processing that context. So, authorization code flow. This is a sort of simplified walkthrough of the flow without looking at any of the actual parameters or values of any of the pieces of information flowing through. We start this flow off by the user visiting the application and saying, I'm trying to use this app, and that's them clicking the login button. The app says, cool, I don't have any way to know who you are yet, so please go over there and go over to the OAuth server so I can get access. That causes the user's browser to go land at the OAuth server with a bunch of stuff in the query string, which will say things like this user is trying to log in to this application, it wants to access contacts. And the OAuth server says, cool, please log in here, which is where the password lives for that account. And then the OAuth server will say, do you approve this request? And assuming the user clicks yes, the OAuth server generates a one-time use code, sends it back to the user's browser. The user's browser takes it back to the app saying, hey, I just got this code from the OAuth server and I'm done over there. You can use this code to now go get an access token. And now behind the scenes, that app can go and exchange that code for an access token, also using its client secret that I got when it registered. The OAuth server applies back with an access token, and now the OAuth flow is done and the app can now use the access token. So you might notice that there are two different color of lines here, and that's because these have a very important difference between the two parts of this flow. The first half, the blue lines, everything is always running through the user's browser, right? So the user, we call that the front channel. Whereas in the second part of the flow, that's actually the app's web server talking directly to the OAuth server over the back channel. And those are pink. The back channel is the sort of like normal thing that you're probably very familiar with where, you know, it's an HTTP client talking to a server that connections encrypted, things like that. We often take it for granted because we use it so much. Front channel is actually the idea that you are using the user's address bar to move data from one place to another. In that flow, we needed to get the authorization code from the OAuth server to the application, but we actually sent it through the user's browser. So the back channel has a ton of benefits, which so many that we just take it for granted and use this all the time. You know, we're going over SSL, certificates are validated, that connection is encrypted and can't be tampered with, things like that. I like to think of that as hand delivering a message where, you know, you walk up to somebody, give them a note, they can see you, you can see them, you can see that they took it, and you both know the transaction has been completed. Sending data over the front channel is actually more like sort of throwing it over a wall and just hoping they catch it. And in this picture, neither side of this, neither cat here can actually see over the wall, which means if you throw this thing over the wall, you don't know whether it's been caught. Hopefully, hopefully it's caught by the right cat, hopefully it wasn't stolen in mid-flight. Similarly, on the receiving end, this cat waiting for this thing to fly over the wall, all it knows is that something flew over the wall, it doesn't actually know that it came from the right place. So neither side can actually trust that this transaction was legitimate or has been completed. So why do we use the front channel at all then? It turns out that there are a couple of really important benefits. And mainly, it's the way that we actually are able to ensure the user has been involved in this trend, in this flow and gave their permission for this access token to be issued. And secondly, it also is a way that the receiver receiving the data means it doesn't need a public IP address, which is really important when we're talking about things like mobile phones or even single-page apps. So, okay, let's walk through this now with URL examples and actually see how this looks. First, the app is going to go and find the URL to the OAuth server, and it's usually reading the docs or there's a way to do it programmatically as well. And then the app is going to put a bunch of stuff into the query string, create a URL, and get the user to click on that. The stuff in the query string is going to be response type set to code, which is how we say we're doing the OAuth code flow. The client ID, which is the app's identifier, it's kind of like the app's username. The redirect URL, which is where the app is waiting for the user to be sent back to when they're done. Scope, which is what the app is trying to access, so if it's trying to access the user's contacts or maybe photos or whatever it is. And then state is a random string the app makes up at the beginning, which is one of the first of these front channel protections. This all gets turned into a URL, which is, you know, becomes the link, the login link. The user clicks that, they log in at the OAuth server, they say this prompt, you know, this application is trying to access your account. And if they click yes, then they get redirected back, and the OAuth server has now issued this one-time use authorization code. And this is actually sent back to the user's browser. The user's browser then makes this request back to the app's callback URL so that the app can take that and exchange it for an access token. This is where that state parameter comes in again. The app just has to make sure that it matches the original state parameter that it made up at the beginning. And this is mainly for CSRF protection, but it also about the, it's also a way to sort of protect the front channel, be a little bit more sure that that code is actually from a flow that the app started. And then the app can say, cool, I got this code from the user, I'm going to go take this code, go over to the OAuth server and get an access token with it. Now this is a back channel request. And this is a post request over to this token endpoint, which is where the access token is going to come from. So first grant type is set to authorization code. You include the code you got from the query string, you include the redirect URL, also the client ID, and also the client secret. And the client secret is the app's password effectively. The OAuth server will see this post request and say, okay, yeah, I know that I issued this code, you know, 10 seconds ago, it hasn't expired yet. And when I issued it, it was for this client ID. And now here is the corresponding client secret. So I know this is actually a request made from the real application and not, and nobody has stolen this code in transit. And the, the OAuth server now returns an access token. So this access token might expire, may or may not, depending on the OAuth server and how that's configured. And if it does expire, the OAuth server might also return a refresh token. So we're now going to dive into more about this access token. You may notice, for example, that in my example here, the access token is a very short string. And that's because that is how some systems do it. So access tokens actually come in a variety of different formats. The idea with an access token is that it is, it is what's known as a bearer token where whoever has the token can use it and go make API requests with it. But even within that, there are multiple different ways that you can implement that. Basically, access tokens fall into two different families. They're either going to be a reference token or a self-encoded token. The idea with a reference token is that this string itself, the token itself, doesn't actually mean anything. It's just a reference to a record in some sort of database. That might be a, you know, a SQL database. It might be a Redis cache. It might be, you know, any other way of storing data. But that string itself doesn't actually mean anything on its own. It's a reference to things like, you know, where the user ID is or where the expiration date permissions, things like that. The idea with a self-encoded token is that the string, the token string itself encodes the data that the resource or the API needs in order to process the request. So if you need to know who the user is, that this access token was issued to or when it expires or what scope it was issued for, you would make up some way to encode that data into a string in a way that is not able to be tampered with and use that string as the access token itself. So then the application, you know, it's going to take this token regardless of which kind it is. It's going to just take this token, put it in an API request and, you know, carry on. The application doesn't care about this difference. The application just cares that the access token will work when it uses it. The API on the other hand absolutely does care about what kind of token it is because the API is the one that needs to be able to go and figure out whether or not to process this API request and who it belongs to, who the user is, when it expires, things like that. So there are no, when I'm saying reference tokens versus self encoded tokens, I'm talking in like the sort of broader sense. There are multiple ways to actually implement self encoded tokens. And the vastly most common way to implement them is by using what's called JSON web token. And that's just a very common standard that is being used by a lot of people to implement self encoded tokens. Now, neither of these is right or wrong. Neither of these is actually better than the other. They are useful in different circumstances. And that's what I want to talk about right now because it turns out that both of these are completely valid. And, you know, if you're building something from scratch, for example, it is important to know that you don't have to use JSON web tokens just because everybody else does. There are a couple of advantages to using reference tokens where it's just a short random string as a record in a database. You know, some advantages are things like if you wanted to revoke that token, you can actually just go and delete it from the database because the next time something goes and looks in the database, it won't find it, which is effectively means it's revoked. It's also possible to then say, show a list of all the active tokens to a user because if you want to go and find that list, you just go look in the database and they're all the active sessions, right? There are a couple of downsides as well. In order to implement this, you have to store all active tokens, which is potentially a lot of data. You know, if you only have like 10,000 users and only a couple of different apps per user, that's not a ton of data. You can probably be fine. But if you start getting to the millions of users, that becomes a bit of a burden on your storage system. But I think the more important downside here is that it forces your resource servers, your APIs to go and actually look into that storage to find out if a token is valid. And that's where it starts to get a little bit hairy because that means every API request has to go look in a database or make an HTTP request out to the authorization server to go and find out if tokens are valid and what they mean. But this does end up being the best option for relatively small scale APIs, especially if your OAuth server is built into the same system as the API. So think like GitHub is a good example of this where, you know, they are a single application and they have their own built in OAuth server. So it makes sense for them to just implement reference tokens because it is a lot easier to deal with because there's fewer moving parts here. But if you want to start scaling your API out to, you know, multiple data centers across distributed regions across the globe, that's where you start to not really want to stash all your tokens in a database and have to go look them up there. So that's where we get to self-encoded tokens. These have a couple of really important advantages. You don't need to store a self-encoded token anywhere because everything you care about about the token lives inside of the token. So, you know, as soon as the API is going to process this request, it can go and inspect the token string itself, extract data out of that and that's how it knows whether or not the token is valid. That means that API does not need to go look into a shared storage to go and validate these. They can validate it locally, very quickly, without doing an external lookup. So that, you know, is potentially is much more scalable, much faster because your APIs can all validate these tokens locally and not have to go into some sort of shared database. However, there are a couple of downsides, which are by no means deal breakers, but we do have to sort of account for these as you're building a system that uses self-encoded tokens like JSON Web tokens. And probably the biggest sort of trick here is that there is no way to revoke a token once it's been issued. Once you issue a JSON Web token, it says how long it expires. It says, you know, when it's valid, which means there's no way to revoke it ahead of time because you can't change the token because the application now has that token. And of course, if you're not storing them, then you can't get a list of all the tokens that are active, you would have to go and add that state back in somewhere. So this does end up being, though, the best solution for, I would say, like large-scale distributed architectures, especially if you're using an external OAuth server. And that is exactly why you see things like, you know, Octa using JSON Web tokens as an access token format. Because as soon as you have an external OAuth server, then it becomes more expensive to have to go and ask it every time whether a token is valid. So you want a way to validate them locally and JSON Web tokens or self-encoded tokens give you that option. So Octa's access tokens, they are self-encoded JSON Web tokens. And that means that Octa has a private key that is used to sign these tokens. And then you're able to use the public key to verify locally without going and looking up in a database whether tokens are valid. This is an example of a JSON Web token from Octa. And if you're familiar with this, you know that there are three parts of this, a header, a payload, and a signature. You do have two different ways to validate this. And I like to call them the fast way and the strong way. The fast way to validate JSON Web tokens is to do that local validation usually using a library where it's going to go and use the public key to check the signature, check the signature of the token, and then you can go and look at the claims inside and decide whether or not the request is valid. And that's going to be by checking things like the expiration dates, checking the audience and the issuer and things like that. I call it the fast way because it can be done extremely quickly. This operation of checking the cryptographic signature is very, very fast and does not need to go over the network in order to do that once you have the keys cached. However, that does mean that you are potentially missing some information which is about whether tokens have been revoked outside of this. Strong validation is the idea that you actually go back and ask the authorization server, send the token to the authorization server and ask, hey, is this token valid? And the authorization server is the one that's maintaining state and understanding whether or not tokens have been revoked, whether users have been deleted, things like that. And you will always get the right answer by asking the authorization server if a token is valid. However, it is slower because it goes over the network. So you've got these two different approaches, right? Fast validation, fast local validation where it is potentially incorrect or strong validation that's a little bit slower, but it's always correct. So let's look quickly at how you do both of these. Here is that example, octa access token. And in this case, I've actually now base 64 decoded the parts. So we've got the header, which talks, which says like, here's the kind of token it is. Here is the signing algorithm used. Here's the key used. Claims is all the stuff that you care about. Things like, here's the user was issued to, here's the scopes that are part of the token, here's the application it was issued to, things like that. The last part is a signature. So what you need to do is find that KID property. That identifies the key that's used to sign it. You need to go find the metadata for the OAuth server, which if you are using the octa admin dashboard, you can go in here, find the metadata URL, click on that, you get this JSON document, which talks about the OAuth server. This is like a bunch of properties of the OAuth server, including like where the authorization endpoint is, but also where the keys live. So this is a URL that says, here are the keys this authorization server uses to sign tokens. If you visit that link, then you'll get this document, which is the actual key data itself. You can use this data. You can use these keys to go and validate the signature by following the JSON web token spec, which is thankfully not anything you have to write code for because there are libraries that will do that for you, and you can just use them to validate the jot signature. So that's a handful of work, but it is actually, once you've got the keys fetched, you can cache those for a very long time because they rotate only like on the order of months, very slowly. So you can cache those keys for a long time, and then you can do this math locally at each API, and this validation is very quick. The other way you can validate these is by going and asking, hey, go back to the OAuth server and ask, hey, is the token valid? You can make this post request. It's called token introspection, and this will go over the network, go back to the OAuth server, and you will get the right answer all of the time as to whether this token is valid. The response will look something like this. It will say active true, and then all the claims get returned as well, and that's how you can, you know, pretend that that JSON web token is actually just an opaque string and still get information about these tokens to know whether or not you should process this request. So here's where it gets a little bit tricky, though. As soon as you, you probably don't want to do this remote token introspection on every request, right, because it's going over the network and you don't want to add that network call into every API call that you're writing. So you might think, well, maybe if I just cache the result, right? Well, sure, but then if you're caching the result, what you're actually doing is building in a new place where that data can go stale. So let's walk through this example. A lot of systems will have an interface like this, where this is actually Twitter, and if you go look at your Twitter security settings, you can see which applications you've granted access to, and you might be surprised at how many you've actually granted access to because Twitter's been around for a while and, you know, it's very easy to just sort of click these links and log into apps and give them access tokens. You might want to go and review these periodically and double check that you actually, you know, are okay with the fact that these applications have an access token that can read your Twitter data or post tweets for you. If you want to revoke one of these applications access, there's a button for it. That's fantastic. The other way, so what that means though is that when you revoke one of these applications from your account, any access tokens issued to this application should no longer work at the Twitter API, right? Which means if it's a self-encoded token like a JSON web token, well, there's no way to change that token and the token has an expiration date, which will still look valid. So now you're kind of stuck if you're only doing local validation. Other reasons tokens might expire or become invalid before they, you know, before they expire, they might become invalid if the user revokes the application, if an application was deactivated by the admin of the organization, a user was deactivated or sometimes if the user's password was reset, the authorization server will also, you know, kill all the active access tokens. And what that means is that depending on whether the API is doing fast local validation or remote slow but strong validation, you might actually get different answers as to whether an access token is correct, is valid. So let's walk through this example. At time zero, you log into an application, it gets an access token, and then you go and send an API request to the API and the API does local validation, which says, yeah, the token's valid, and then does remote introspection, you know, asking back to the OAuth server, and the OAuth server says, yes, this access token is valid. They agree. Great. Okay. An hour goes by. Same thing. This token lasts for eight hours, right? So an hour later, both still agree. Two hours go by, and then the user goes in and revokes this application's access. And now on hour three, when the application goes and makes an API request, local validation still passes because as far as the JSON web token is concerned, that, you know, the expiration date is still in the future. And it's like, cool. But if you were to go to remote introspection, the OAuth server would say, no, that access token is not valid anymore because the user revoked the application. And now you've got different answers happening for whether a token is valid all the way up until the access token expires. And this is kind of a tricky situation because what's the right, what's the right thing to do here, right? Do you want to have always the right answer, but have that added network cost in? Or are you okay with the fact that you might be having the wrong answer about whether tokens are valid for a little while? And it turns out, so oh, yeah, and then caching, as far as caching goes, if you were to add your own caching of this remote response, you've effectively just built a new one of these lines in this graph, where you've got now a new buffer about whether or not an access token looks valid. And what's really bad about that is that the API controls it rather than the OAuth server, so that the, where normally you want to push this logic into the OAuth servers that you can actually tweak it there and change the behavior there. So, yeah, what's the right solution here, right? It seems like we're in a bit of a sticky situation. And it turns out that there isn't, again, a obviously correct answer, but there are a couple of ways you can sort of work around this or actually get the best of both worlds. So this ends up being a very common pattern, which is having some sort of API gateway out in front of your system. That might be an actual API gateway, like Apigee or something, or an Amazon API gateway, or it could just be a piece of middleware in your Java app that's doing, that's acting as a gateway before it actually goes and calls methods in your code. But in any case, that API gateway is the one that's going to always do local validation. And the reason they can always do local validation is because local validation is very quick. All it has to do is cache the keys from the OAuth server and then do a little bit of math on the token signature and check whether it's valid. Cool. So API gateway is processing requests, it's handling, it's out there on the public internet handling all sorts of junk from all over bots and attacks or just random expired tokens and it's able to reject all that bad traffic very easily. And then it passes only to the back end when the local validation passes. So if the access token has a valid signature and has not yet expired according to the timestamp in the JSON web token, it'll pass that traffic back. That does mean that it is passing back access tokens that may have been revoked. And what it also means is that it's rejecting the vast majority of the bad tokens without a lot of cost. So that's great. And then your back end APIs now know that any request that comes into them is actually already passed local validation and then it's up to those APIs to decide whether or not local validation is enough. And it might be enough in sort of relatively not super sensitive APIs. Like if you have a customer API that has a method to return a user's profile photo and if an app calls that API with a revoked token, it's probably not the end of the world and it's probably okay to return the profile photo anyway because that token was valid at one point, it's just that it isn't actually valid right now. And however, if you have an API that's going to go and charge a user's credit card or actually go ship an order, then you absolutely do not want a revoked token to run that API method, right? So in those cases, those back end APIs themselves can decide, okay, local validation, I know that that passed because the API gateway said it was fine, but that's not enough for me. I now need to go and check, is this token really valid? And it does that by doing the token introspection, which is slower and goes over the network, but we'll always get the correct answer. And the benefit of this is that this is only actually happening on a relatively small percentage of API requests compared to what's coming in at the API gateway. So that way, you can sort of get the best of both worlds of, you know, you get the benefits of the scalability of local validation of JSON web tokens, but you also get the reliability of the slower token introspection that requires the network call. The other factor you have here to work with is that, and this is why I mentioned that it's a good idea to make sure the OAuth server is one controlling these policies is that you can actually sort of affect how you want this to behave by deciding your token lifetime. So how long access tokens should last? Again, there is no, there is no right or wrong answer. There's no hard and fast rules. There's just a lot of tradeoffs in this. And you can actually use this to your advantage to, again, take advantage of the fact that these APIs might be doing both local and remote validation to, you know, get the best of both worlds here. So let's look at some examples. Your, you might have a policy that says your admin users get access tokens that are very short lived, one hour long access tokens. And that way, the longest amount of time that some API that's only doing local validation could even potentially have the wrong answer is capped at one hour. And that's, you know, a pretty reasonable solution to that where you're like, okay, fine, you know, if an app, if someone goes in and revokes the app, and the app still goes and makes a request, that's at least only going to do damage for the next, at most one hour. And then you would issue refresh tokens to those applications that last 24 hours. And that's a way to force that force admin users to log in every day. You know, at the end of the day, the refresh tokens expire, the app has no way to get a new access token without getting the user to log in again. So that's great as well. On the other hand, for consumer users, you probably don't want someone who's downloaded your mobile app to have to log into it every day. That would be incredibly frustrating. So what you do for those users is because they're also probably doing less sensitive operations. You give them 24 hour long access tokens, and then you give them unlimited refresh tokens. Unlimited refresh tokens means that effectively they will look like they're logged in forever. You would, of course, you know, use secure storage mechanisms to store that refresh token, like you can put it behind Touch ID on an iPhone and require that they use, you know, Touch ID or Face ID to unlock that secure storage, and then go and use the refresh token to get a new access token. But as far as the user is concerned, what they're going to see is that they don't have to log in again. They don't type in their password, they just do Face ID and then they're logged in. And on the other hand, you might have privileged scopes, things like, you know, modifying user data and having modifying a customer's data or a customer placing an order, things like that, where you can actually say, well, for those specific scopes, I'm going to issue, if an application needs that scope, then it's going to get an access token that only lasts four hours. And that way, and no refresh token, that way, you know, the system can ensure that users are actually, users actually have approved this request very recently. And you can do all this together at the same time, because you can actually make these policy decisions differently depending on the users and the context of the requests. That's one of the things that is actually in the, in octa, which is really cool, which is you can go and create all these policies, check these boxes, depending on the grant type, depending on the user's groups, depending on the scopes, part of the request, you know, and that's all going to be a way to decide your access token and refresh token lifetimes. And you can define multiple, multiples of these rules, and they stack up as well. So I hope that gives you some ideas around dealing with, dealing with access tokens, dealing with token lifetime considerations, and yeah, it gives you some, some things to think about. I'm going to take a look at some of the questions. The, there's a question here about, do you have an idea how one could ensure that the back end APIs are at least doing local validation of the token and not just trusting the API gateway? I mean, I think the only way you can really ensure that is by double checking the code. So if you've got this situation where, you know, you've got an API gateway doing local validation, but then you also want your back end APIs like this customer API to also do local validation. There's not really a way, any way you can enforce that at the authorization server layer. But also it's not, if that, if that API is not actually on the public internet, it doesn't, you don't really need to do local validation again, because you're not gating anything by doing that. If it is public facing on the internet, then you, of course, it would need to do local validation itself, but I would not recommend doing that in this pattern, because the whole benefit of this pattern was to have the API gateway doing local validation. There is another question about, let's take this one, what possibilities do you see for developers to not get confused by a little different types of tokens and different flavors they come with? Yeah. That is a, so that's definitely a challenge. And I think one of the really confusing parts about this, which I'm a little, a little sad about honestly, is that the, so the access tokens are jots. I'm looking for this slide where I have a JSON web token access token. And you know, this JSON web token access tokens are great, because it's a standard format. There's good library support in many different languages. The downside to using these as access tokens is that they look the same as ID tokens in open ID connect, because open ID connect ID tokens are also JSON web tokens. And that actually is defined by the standard. So open ID connect is always going to have, you know, JSON web tokens as that token format, whereas in OAuth, you could do, you could do anything for your access tokens, some other self-encoded format. So the downside is that they look the same, which is very confusing to developers because it means that developers are going to get both tokens back from the OAuth server if they're trying to do open ID connect with OAuth. These tokens start off with the same three characters, and then they look very similar after that. But they do completely different things and they cannot, absolutely cannot be used interchangeably. They are for completely different things. And it is a little bit too bad that we're in that situation, but you know, here we are. And I guess we just have to deal with it. I think the best thing to do is just to continue, you know, teaching, teaching developers to always treat access tokens as, you know, if you're building a client, you always treat an access token as an opaque string. That's this slide here, right? If you're writing an application and you just got an access token, you're trying to go make an API call, you just treat that as an opaque string and you don't look at it, you just put it in the header and make the request. Whereas the ID token is actually meant to be parsed by that application to be understood so that it can extract things like the user ID. Okay, another question about, should we be storing refresh tokens in the browser or on the server allowing a valid maybe expired token to get the refresh token? Yeah, this is tricky. So browser-based apps, this is a whole thing, which I am writing that draft spec for, which is recommendations for doing OAuth for browser-based apps. And it turns out there's a couple of different scenarios. And they have different trade-offs, again, as usual, which you'll notice is a common theme here, nothing is perfect. The one way to do this, I'm going to see if I can pull up my diagrams here. One way to do this is to actually let the browser have refresh tokens and access tokens itself. So I'm going to screen share and you should hopefully see my draft here. So this is the spec OAuth for browser-based apps, the recommendation that's currently in the works. I have another version coming and then it'll go into the finalization process. But in here, it describes three different architecture patterns. And these are sort of, this is meant to outline the three different options you have, where if you have a JavaScript app that has no backend itself and it's going and talking to resource servers directly, that's where it would actually have a refresh token itself and it can use the refresh token and go to the OAuth server itself to get new access token. That's definitely a way you can do it. This is the diagram here where your application is being served by a static web host, and then the application is running in a browser, it's going and getting access tokens and refresh tokens and then using the access tokens over here and sending the refresh tokens back to here to get new ones. That works. That basically moves all of the OAuth logic into the application and then you kind of avoid a lot of the weird cases you get into if you start trying to deal with adding another layer of session lifetimes or things like that. The other pattern that's very common is this one, which is actually to go and push all of the OAuth logic into an application server. This is a very common pattern people use to develop single-page apps where it's not a literal static application with just JavaScript files, but that JavaScript is served from a dynamic server back in, which has the ability to run code and also do things like hold on to client secrets. In this case, the application server is the one that's the OAuth client and it's the one that gets an access token and a refresh token and it's able to go make API calls and then go get new access tokens. The way that it talks to the browser is through normal browser cookies where it might just be like the whatever session mechanism you have in your web framework, then you would use that as the cookie. That way you can control the expiration of that independently of the expiration of your OAuth. I hope that explains some of those architectural patterns. There's another question here. How do we use the password grant for public clients? That's a fun one. One of the things that the latest developments in the OAuth group is the security best current practice, which is in last call right now. That document actually is deprecating both the implicit flow as well as the password grant completely and saying you just should not use this. The reason for that is because it is not really possible to make a secure implementation that allows the password flow. The reason for that is because that means your applications actually have to hold on to the user's password and go and exchange the password for an access token, which was the entire thing OAuth was created to avoid doing. It's really not a good idea to do that and I would definitely not recommend doing it. Instead, you're going to want to look for solutions that do an actual OAuth flow properly where you actually redirect out to the OAuth server. That gives you so many benefits. One, it's more secure. Two, it actually means you can do multi-factor OAuth as well without messing with your client code. If you imagine you've got a single-page app doing a password grant or any application doing a password grant and you wanted to add multi-factor OAuth to it, well, you're kind of just on your own because you now have to first exchange that password for something and then somehow decide how to challenge the user for another factor. You're kind of just on your own making that up as you go along. Whereas if you use OAuth and redirect the user out to the authorization server and not ask them for their password in the application, then it's the authorization server's business to go and get them to log in with their password and then do multi-factor OAuth. That's all just dealt with on the authorization server, which is where those credentials ultimately live. It's much more secure having that being in just that one place and not having apps have access to it. It's also a lot more flexible. It means you can do things like you can decide. We're going to add a new multi-factor method, multi-factor OAuth method support. Today, we only support UB keys. Tomorrow, we're going to add support for WebAuthN. Well, if you're always sending the user out to the OAuth server, you only need to modify your OAuth server to support WebAuthN and all of your client applications get the benefit from it right away, which is a huge deal. It means you don't have to go and touch 100 different applications and modify them to all add support for the latest multi-factor OAuth method. This was not really an answer to how you use password grant for public clients. That was mostly saying not to do it, which I would strongly recommend not doing it. However, the password grant itself is technically possible to use with public clients. You just don't include the client secret in that request. You can see why that might also be bad because it basically means now your token endpoint is able to go and exchange user names and passwords for access tokens where that starts to look like a very attractive target for hackers to try password dumps and try to get access tokens at your service. Another good reason to not use the password grant for public clients. Cool. We are 10 minutes from the end. Feel free to drop more questions in. I'll take this one. Can you give a description of rich authorization requests? Rich authorization requests is a new spec coming out of the group. I'm going to talk about this with going back to our original example of the authorization code flow. In the authorization code flow, the client first has to build this link up. By building this link, it's adding things like its client ID, its redirect URL, and the scope. All this information about the authorization request. This is what OAuth defines at its core. Rich authorization requests is the idea that sometimes scope is not actually enough to describe what the application is trying to do. In this case, the application is saying I'm trying to go and access, read and write this user's contact address book. That scope is defined at the resource server. The resource server understands that when the access token has the scope in it, it's allowed to do these five API methods. That's a pretty coarse scope, I would say. The example used by this rich authorization request draft is in banking. If you imagine you have an API that is going to let somebody send a payment to another person, you might have an application that wants to make a request to go and send, make an API request to go and move money from one account to another. You might want to allow that application to, you might want to limit what that application can actually do. You might want a request that says this application is trying to move $10 from this account to this account. If you try to describe that in scope, you can see why it doesn't work. It's not a single scope. The dollar amount is an arbitrary number. The account numbers are arbitrary, so there's no way to cram that into the scope parameter. What rich authorization request is doing is adding on a whole new way of describing these rich authorization requests. That is a way to encode a lot more data about the request beyond just, I'm trying to read this person's address book. I will drop a link to that in the, oh, we don't have the group chat in this one. I'll share my screen to show that one. The link to rich authorization requests, whatever, you can just Google it. Rich authorization request, oh, you'll find it. There's a medium blog post about it, and the spec is the second result. Okay, a couple more questions coming in. See how many I can get through. Is there a, oh my gosh, okay, what's the main reason the implicit flow is being deprecated? The main reason is because the implicit flow is created when under constraints that basically no longer apply. When the implicit flow was created, there was no such thing as cores, and we, you know, JavaScript APIs worked very differently. Over the last 10 years, things have changed dramatically, and we have way better tools, and you can do authorization code flow with Pixi in a browser, and it's totally doable. I have a blog post that talks a lot more about that. If you go to, if you search for, is the OAuth 2 implicit flow dead, you'll find the blog post in that blog post that talks about these in more detail, and also there's a video which explains those same things in a longer form. Okay, next question. Is it the best practice to use the OAuth code in Pixi with confidential clients as well? And the password and implicit are going to deprecate for confidential clients also? Yes. So the security best current practice says the new best way to do this is to use OAuth code in Pixi for everything, including confidential clients. And it also deprecates the password grant for every, for all kinds of clients, and the implicit flow is deprecated as well. So that is an excellent summary. Is there a client side method to query the authorization server for available flows and queries? There is. When we went and looked at that metadata URL about the OAuth server, this is the, it's called the metadata URL. And if you search for that, it's like actually a don't spec, which is part of this maze of specs. But if you notice in here, there are things like response types supported and response mode supported grant types supported. And that will tell you what the server supports. And that's what a client can use to actually decide about how to interact with the OAuth server. Okay, this is a good one. Is it, is it bad to use the state parameter for more than just a handshake? Can you keep application state in this value? So this is a great question. And originally, well, let's go back to the example in my authorization code diagram, where, where we talk about these parameters. So we didn't talk about pixie. But what pixie does is adds a sort of new dynamic secret into this flow as well. And pixie solves two things. Pixie solves, when you don't have a client secret, it ensures that that this authorization code flow is still secure. But it also has sort of like a side effects side effect prevents CSRF attacks. And state, the state parameter is meant to protect against CSRF attacks. And the state parameter can be like the easy way to do it just to generate a random string and stash it in a session somewhere. But you certainly can encode data into that state, you just have to make sure that it's unique every time. However, if you're using pixie, then pixie solves CSRF for you. And you now can use state as a simple method of encoding application state without having to worry about it being different every time. So that's a kind of nice side effect of using pixie for confidential clients, which is that you now get to use the state parameter in the sort of easier version, easier way as well. We are almost out of time. Let's see if I can do one more question. Is there an update planned for your OAuth 2 Simplified book? Yes. So I have written this book called OAuth 2 Simplified. And you can actually get a copy of it at OAuth2simplified.com. However, this is the latest update to this book was over a year ago. And a lot of these recent changes like the security best current practice is actually newer than that. So I am planning on doing an update to this book, which we'll talk more about the current recommendations. So keep an eye out for that as well. The book is also available on OAuth.com, which is like the ebook or not ebook version, it's just a website. So all the chapters are web pages, and you can just browse around and read it for free there. There's no download option, but you can just browse the website to read the book there. So we are just about out of time. I want to leave you with some links to some other places to go for the reading. And I apologize if I didn't get to all the questions, but I'm always happy to talk offline. And we can keep discussing this stuff later and always happy to have more people involved in the development of the spec as well. OAuth.com slash playground is actually a great way to go and try out a demonstration of all the flows. It's an interactive walkthrough of these flows. And the website OAuth.net again is the community website of OAuth. There's a lot of good resources. A lot of the things I was explaining and links to these blog posts I was referencing are available on here. So if you go there and find the implicit grant, you'll find all the resources about the implicit grant there. Myself and coworkers blog on the Octa Developer blog a lot. So that's a great resource for things like talking about OAuth and also talking about also full-on tutorials about implementing OAuth in different languages, different frameworks and things like that. If you want to try any of those blog posts out and tutorials out, I do recommend getting an Octa Developer account. Specifically, developer account. Make sure you go to developer.octa.com because there you can actually sign up and get a free account. It's free forever. It's just limited by a number of active users, but it's a great way to go and try out all the, try out the spec, try out the framework you're using, the language you're using, try out these libraries and get a sense of what it takes to do that. So I will leave you with this wonderful cat and thank you all very much for attending and have an excellent rest of your day.