 This session is going to be all about protecting an API using OAuth. Now, if you were here in the morning for the first session, I talked a lot about the sort of API or the OAuth client side of things. So I was talking about how to get an access token, how to get an ID token, how to learn who the user is. We're going to put all of that aside now and sort of assume that it's done, assume that that's a solved problem, and we're going to focus on just the API piece now. So I want to start with a couple of slides. Here, we're going to do the same sort of thing where I'm going to be talking about these ideas and what we'll be doing throughout the session, and you will be able to follow along the session as we go. And I will also then open up the document I'm going to share with you when we're doing those exercises. So again, this morning's session was mostly about how these two pieces of the puzzle talk to each other, how the OAuth client can go get an access token and use it. And what we're really going to focus on now is more about how these two things are talking to each other, how the OAuth server and the API can work together to we're going to assume the client is just sort of out there in the world somewhere. Okay, so for the exercises here, what we're going to do is we are actually not going to be writing any code. We're going to again, because we're assuming that the OAuth client is already built. It's already built by somebody else, some other team that was done. That code already exists. If you have an OAuth client that you are already able to pop in new configuration too really easily, you're welcome to use that. Otherwise, I have one that you can use for the exercises and I'll share the link to that when we need it. Really what we're going to be focusing on are the details of what exactly it means to be validating an access token when you are an API, when you're building the API. And that's really the focus of the session is mostly around access tokens. There's a lot of different considerations that go into the decisions that you'll make configuring your OAuth server and deciding how to validate access tokens, what things to keep in mind as you're building this out. So that's really what we're going to talk about. Now, before we get started on the octa part of the lab, I do want to go over some of the sort of general OAuth concepts around this. So again, I like to use this analogy of access tokens being like a hotel key, where you walk up to the person at the front desk and you check into the hotel. They give you a hotel key, which you can use to then go and access things in the hotel, like the room of your suite or the hotel pool or the gym. That key card gives you access to resources in the hotel. So in OAuth terms, that key card is like the access token, where it represents not you as a person, it represents that you have access to various things in this hotel for a limited amount of time. And that's the same thing that's true with an access token. It is very likely that an access token is going to give you access to some sort of API in some way, how that actually happens is what we're going to focus on. But it doesn't necessarily have to be based on an individual user. It doesn't have to represent a single person. The door at this hotel doesn't actually care about me. It doesn't care about the fact that I'm the one going to the room. All it cares about is that a authorized key card is opening the door. So that we can think of access tokens in OAuth in the same way. And again, as we sort of looked at in the beginning session this morning, OpenID Connect is what fills in that sort of missing piece as far as applications go, of if the app needs to know about who the user is, learning about their email address or their name or anything like that. It's a different story when we're talking about APIs, because APIs are never going to be seeing ID tokens, because that's not the audience of the ID token. The ID token is not meant to be seen ever by APIs. Your APIs are only going to have access tokens sent to them. So let's dive into some of the details about these access tokens. So again, before we get into the Octa specific bits, I do want to point out that not all access tokens are the same. There's actually an infinite number of ways to implement access tokens in an OAuth server. It's typically the OAuth server that's making that decision as to how access tokens work. And then as you're building the API, you're going to have to be aware of what decisions it made and be aware of how to validate access tokens, but you won't necessarily get to make the decisions about what the access tokens actually look like. In particular, there are two general ways that are possible to create access tokens, either a reference token or a self-encoded token. And it turns out both of these actually have both disadvantages and advantages. Neither of these is a perfect solution. So the idea with a reference token is that the token itself is just a random string of letters and numbers and whatever characters, and it doesn't mean anything on its own. It's actually just a pointer to data somewhere. So that is a record and a database or something in a cache layer of some sort. It doesn't matter what the particular mechanism is. The point is that the string of that is the access token that's handed to the application does not have any inherent meaning. It's kind of like if your driver's license were just a document number written on it. The only way that anybody looking at that would be able to know what it means is to go and ask someone else. Go ask the issuing authority of the driver's license or the passport, which as you can imagine probably pretty quickly, that would run into some pretty serious scaling problems. If everybody who ever had to look at a passport to validate it had to go and call the passport office to check if it's valid. It's not going to scale very well. And that's really where self-encoded tokens start to become more appealing. The idea with a self-encoded token is that you take the information about the token like who it was issued to, which app it's for, the lifetime, anything associated with that authorization and you actually turn it into a string in some way, pack it up, turn it into a string, sign it, encrypt it, or both. And that becomes the actual access token, which means that does have an inherent meaning. There is someone, the API, the resource server can look at it and see this is what it means. And that's more like how actual driver's licenses work, where you don't have to, as someone who's validating your driver's license or your passport, they don't have to call up an office, they can just look at it and see if it's valid. So, okay, there's two ways to do it, right? So within each of these families, there's any number of actual practical implementations of them. And the details of those aren't necessarily that much different from each other within these families. All reference tokens are going to involve looking up the data in something, in some storage, which is going to have usually the same exponential, within the exponent number of, you know, the same cost of looking that up. Whether that's a network request over HTTP or a database lookup that's still over the network, those are all going to require a lookup, whereas a self-encoded token can be inspected itself immediately, and there is no network cost to doing that. Within self-encoded tokens, there's, you know, any number of different ways to do it. You can make up your own scheme, you can use, there's actually a lot of web frameworks that do self-encoded cookies instead of server-side sessions. That's a very normal thing to do as well. But a very common one that's used in the world of OAuth is JSON web tokens. And that is probably because Open ID Connect requires JSON web tokens. That's part of the Open ID Connect spec. And that made it, meant that there was a lot of good tools built up around it and good library support for it. And then it just kind of was a natural choice for many OAuth servers that are implementing access tokens. But it's by no means the only way that access tokens can work in general. So, okay, let's get into some of the problems, but also advantages of both of these kinds of tokens because we're going to have to be aware of the limitations and the advantages in order to actually design a good system. So reference tokens. If your access tokens don't mean anything by themselves, there are some advantages to that. Primarily the advantage is how simple this ends up being in terms of understanding the implementation and understanding the cost associated with various parts of the system. If you want to revoke a token that is a reference token, you can just delete it from the database and it'll be gone immediately and nothing, anything that is going to be validating that will no longer find it in the storage, so it will be effectively immediately revoked. Another advantage is that anything that you're storing or associating with the token isn't visible to anybody with the token. So who has the token? It's the OAuth client, right? So that means your, the actual end user who is using the client will probably be able to at some point if they wanted to get a hold of the token that was for themselves and your app developers during the course of development will be getting tokens issued to them as they're trying out and testing out the app. That means anything that you've put in the token is potentially visible to your app developers and end users. So, or rather reference tokens, it's not visible to those. Okay, so downsides. The couple major downsides, you have to store every active token otherwise it doesn't exist. So maybe that's not the end of the world for your particular case because you only have like a couple, 10,000 users or so, the storage costs aren't extremely high, storage is cheap, but the bigger downside is the network cost of validating those tokens because you have to look in the shared storage. So it's going to be probably at best a database lookup or in some sort of light caching layer and at worst it'll be an HTTP request which is probably slower than a database lookup. Okay, not necessarily deal breakers. In fact, we do see this very often in the sort of smaller scale, especially consumer APIs, but in particular if there is an integrated OAuth server, what I mean by that is GitHub is a good example. GitHub is a single system, there's one OAuth server, it's GitHub, it has one API, it's the GitHub API, those are the only that's the only pair that exist for both those systems and it's one piece of software, right? It's run by GitHub. So it makes sense that their tokens are reference tokens because they don't really need to take advantage of the, they don't need the advantages of the self-encoded tokens and it ends up being just sort of simpler to understand. Okay, let's talk about self-encoded tokens and, for example, JSON web tokens, which are not the only form but a very, very common form. One of the big advantages is that you don't need to store these anymore. Once an authorization server can create one, it's signed, it lasts a limited amount of time and it's packed up and shipped over to the client. That means that the authorization server can just forget about it because when it needs to know if it's valid, the client will be bringing it back. So there's no storage requirement, which you can imagine why that might be useful is if you're trying to build a massively scalable system. But I think even more importantly than the storage is the ability to validate these tokens without calling back to the OAuth server and that is, that means the API your resource servers can validate these tokens by just inspecting them and deciding on their own because they can do the signature validation required to check if it's valid. That's very cool because it means a lot less network traffic involved. However, these are very good things. There are some downsides. Your self-encoded tokens, once one is created, it'll say how long it's valid. That whole string is handed to the client, which means there's no way to change that. You can't revoke them. You can't modify them. That token exists until it expires. And if you're using a format like JSON WebToken that does not encrypt the data, then anything you put into the token is potentially visible to users and app developers. So even though there's these sort of weird workarounds, this does usually end up being the best option for larger scale distributed architectures, especially if you are using an external OAuth server that's not part of your API. And that's exactly the case when you're using something like Octa or Auth0, where those are external systems. It is an OAuth server as a service and you're building an API that is a separate piece of software. So let's talk about Octa's access tokens. Octa's access tokens are self-encoded tokens and they are JSON Web tokens. Again, because it is broad library support, it's a well-understood standard and makes a lot of sense. The authorization server that is on your account will have its own private key and it uses that to sign the tokens so that your APIs can validate them without asking Octa. So let's take a look at one. It's going to be a JSON Web token, so we know it's a three-part token and there's two dots in there somewhere if you look closely. If you split on the dots, you get the three parts, the header, the payload, and the signature. So the header is information about the token, that's going to be things like what signing algorithm was used, the identifier of the key that was used, which is an important one, and then the rest are claims. And we're going to get into these claims very shortly. That key identifier is actually telling your JSON Web token library which key signed the tokens so that it can validate the signature, which is that third part. So if we go into our metadata URL, which we used a bit this morning, one of the properties we didn't look at yet is this gwksuri, which is where the keys live. Now, don't worry about it. This is the actual key material, public key material. A JSON Web token library will know how to use this and validate the signature. And yes, you should definitely use a library because writing cryptography code from scratch is not a good idea. The good thing is there's lots of JSON Web token libraries. So let's go ahead and start setting things up because I want to show you a real access token as quick as possible here. So what we're going to do is I'm going to drop a few links into this chat here. They are also linked from the workshop page here, so you should find them below already. The exercise that we're going to be doing is linked from, it's the lab instructions link and it's this Google Doc page. There is the link. And what we're going to, we're going to work through this session. So this is going to be what we're following for the rest of this course. There are a couple other tools we're going to use in order to actually work on this. You'll need an octave developer account, of course, so make sure you've gone ahead and signed up for that. And go log into that. And then we're going to use these other tool links, the two links. We're going to be working through this page, this page on OAuth.school, which is the website I use for these workshops. This is the goal of the session. The goal is to tick off all of these boxes. And the first person who does it will win a UV key of their choice out of these four. And everybody who finishes it today before the end of developer day will get a copy of my book. So the race is on. When you tick off all the boxes, it'll then have a spot where you can enter in your shipping information. And I will send you a copy of my book. So what do we have to do? We have to build an OAuth client. You don't actually have to build one because I have one made for you, which I'll show you in a second. You can use it. You can use your own. Either way is fine. But you have to paste a token into this website in order to check if you've finished it. It has to be issued before the end of this session. So I think that's 5.59 my time, and it's 4.19 right now. So I actually gave you an extra half hour. It has to be active, which means it can't be expired when you paste it in. It makes sense. It must be issued to a confidential client. Now, I'm not going to go over the details again of these because we talked about that this morning, but a confidential client is just an app running on a server, which means it has a client's secret. And that just means when you go create the application in Okta, make sure you choose that you are building a web server-based application. Okay. Then here's the ones that are where we're going to have to do some work. The token has to last for at least two hours. By default, Okta's access tokens last for one hour. It has to include a custom scope called developer day. It also has to include the custom claim favorite color. You can set the value to whatever you want. And I will show you how to do all these shortly. And it has to be from a new Okta org. So just make sure you go make a new Okta org for this. Don't use a production org, please. Okay. That's what we're going to do. Get started. And here's what we're going to be working through. We're going to be getting an access token, pasting it in here, and seeing how many of the boxes we check off. So first things first. So again, all of these instructions are written down in the Google Doc. The API security challenge, protecting your APIs with OAuth. Looks like a bunch of you are in there. That's fantastic. So we're going to go ahead and start working through this. Make this a little bigger. Great. So first things first, register for an Okta developer account. I'm going to assume most of you have already done that. So I'm not going to do that again from scratch, although I will go ahead and log into mine. And since I've probably got logged out by this point, since I logged into it earlier this morning, let me see if I have that the org I was going to use for this that I cleaned up beforehand. So it was the one down here. Okay. So here's my Okta org. I think now I realize I may need to actually reset it properly. Yeah. Okay. I had to go make all the screenshots for you, which means I'm done technically. So I need to undo all that before we get started so I can follow along with you. We're going to delete the custom claims and revert the policies back to a normal account. Okay. Now we're back to normal. So when you have set up your account, you will have basically nothing in it. There'll be no apps or anything. So we are ready to go ahead and start. First things first, register a confidential client. And again, this is, that just means that you need to have an application created that has a client secret. So we're going to go applications, applications, create an app integration, create an OIDC app, create a web application. This is for server side apps, which means these are the only ones that get a client secret. The rest of these do not get client secrets because they wouldn't be able to keep the secret secret. We're going to call it challenge app. We're going to leave everything there, the defaults. The redirect URL is the important one. So this is where the Okta is going to send the user back to after they've authenticated. So we need to know where we're going to be launching our app. Now this is where I've saved you some time. If you don't have an OAuth client created already, then you can use mine, which is at this link. And I see I've got some cookies saved. Okay. That's going into the chat. Example app.com slash client. This is actually a really cool tool. This is a completely generic OAuth client that follows spec, the standards. So it has nothing to do with Okta, even though the placeholder URL says Okta. What it does is if you put in your issue or URL, identifying your OAuth server, and if that server supports discovery, open and connect discovery, then it will find the authorization endpoint and then it knows how to do a flow. And this is a sort of debugger. It's going to show us the request it's making before, and before it actually makes the request so we can see what's going on. So I need to configure this by giving it my issue or URL, and then giving it the client ID and secret for the app I just made. And then this will be our OAuth client for the exercise. So, oh yeah, the point of that was because this is going to be used as the redirect URL in the application I'm creating. It's just one file. It's actually a very small amount of PHP code that's doing all of this, which is all in one file. It is the, presenting this form, it's doing the code exchange and getting the access token, and it'll show us back the access token at the end. So I'm just going to copy that in to the redirect URL field, and we're going to assign this to everybody in the org, and we're going to save it. So now we've got the client ID and client secret, so I can copy these into the config. This would be like defining your application's config file. So now let's see. We've created the client, need to assign to everybody, click save, okay. Find the issuer URL. This is again, this is the identifier of the OAuth server. So we're going to go to security and API. We're going to see that. So we're going to go to security, API, and we will see here is my issuer URL. This is the identifier of the OAuth server. So the OAuth server can, you can configure this with a bunch of different rules, and this is where we're going to be spending most of the time today. The metadata link is how the OAuth client can find information about the server, like its authorization endpoint. So we're going to take that issuer URL, put it here, and now we have the OAuth client ready to start a flow. So okay, how are we going to start the flow? Well, we need to request some sort of scope. So for now, what we can do is we can request just a scope open ID just to give this a try because we haven't made any custom scopes yet, and you can't request no scopes. So we're going to request just the scope open ID just to see how this works and see that we can use it to get an access to start the flow. All that did is it saved our config into the session for this, for in my browser, and then it built this URL. So it found the authorization endpoint from the issuer URL metadata and then it added all these parameters into the query string. So it's gone and done, it's created a random code verifier, which I can't see, it's just on the server, it's created the hash of it, the code challenge, generate a random string for state, it's properly encoded the redirect URL, it's got our scope that we plugged in, and the client ID. So this is showing you what your real application would need to do to start the flow, just build this URL. That is also then put on this button that says continue. So when I click this, I'm going to be visiting that URL. Now I'm already logged in in this browser, so it's going to be very quick, you're not going to see it happen. I'm going to be sent to octa, because this is a link to octa, and I'm going to be sent back. Again, very quick, right? You didn't even see it, but if you look at the network tab, you'll see that it happened. I got sent to octa, I came back with an authorization code in the URL. It's showing me the authorization code here, but it's also then showing me what it's about to do to go and turn that into an access token. So it's going to go make a post request to the token endpoint, which it also found from the metadata, and here's what it's going to put in the post request. Grant type authorization code, it's going to put the code verifier, which is that random string it made up that it used to calculate the code challenge. It's going to include the redirect URL, client ID, and client secret. If I click post, this server will go and make that post request to octa and show me the response, which sure enough is an access token and an ID token, because I requested the scope open ID. We don't care about the ID token for now, because all we're trying to do is configure access tokens. So if we take this access token and go back to this and paste it in here and validate, we're going to see that we've made some progress. This sure enough is an active token. It was issued before the deadline, which is 90 minutes now, and it was issued to a confidential client. So we've made it that far, but we need to figure out how to do these, and then we're going to talk about why. Okay, so I think I just skipped through all this in, I think I just did this, I don't need to show you the slides or the doc again, response from the token endpoint, that's what we got, paste it in, check your work. Only a few of the boxes are done, or check because we haven't configured the rest of the policies. Okay, how are we doing so far? Any questions? Let's see if there's any, if we got any questions or if people are making progress. Oh, yeah, lots of people are making progress. That is awesome. I love it. Okay. And so we have, next thing we have to do is configure the token lifetime. We're going to talk about why we would configure the token lifetime in a second, but let's first just see how to do it. So, changing the token lifetime. By default, actually, let's, yeah, let's take a look at this. So when I paste the exit token in, I should really make it just stay in that box, but this tool is telling us what it found inside the token. It's telling us the issuer, it's telling us all the claims inside the token. So it's got the issuer, it's got the audience, it's got timestamps, client ID and user ID. These are all the claims in the token. But you can see there's not that much, right? This expiration date is, let's see, that looks like, yeah, that's 3,600 more than that. So that's one hour. We know the token lasts for one hour. And actually, if you look at the response from Okta, the full token response actually says this token expires in one hour. So we know that our token lasts only one hour, and that's the default policy in Okta. So we want to change it to two hours, at least. So we're going to go back to the sidebar, go back to configure that OAuth server. This is going to be a common pattern. You should get used to going to security, going to API, clicking on your default OAuth server, and then this is where you can configure it. Now we're going to go into access policies. And by default, you will have just one rule in here, applying to every client, all scopes, everything. That's fine. We're just going to edit the one policy. We're going to edit this rule, and we can see, we get a bunch of options. We've got options for whether this rule applies to certain grant types, whether it applies to certain users, whether it applies to certain scopes, which we haven't even done yet. But if the conditions of this rule are met, then the outcome is changing the token lifetimes. So we're just going to change that to two hours. We're going to keep refresh tokens as it is. And go ahead and update that rule. That's all we did. We're just going to go back here, start over. It saved my stuff in here, so I don't have to type it again. And then we're just going to start the flow. It builds a slink and nothing's changed. The client doesn't know that the lifetime is different yet. We're going to exchange that code for the access token. And now, sure enough, our token lasts for two hours. So if I paste this one in here, we should get the checkbox for the token lifetime. Awesome. Okay. So I see that we've got a lot of people have already figured that one out. That's great. See, making progress. A few more people are going to be working on that. Let's talk a little bit about this concern, though, about why we care about changing the token lifetime. You might notice that there are some limits on the values. So if I, for example, try to say seven days, I'm going to get an error because Okta actually limits the access token lifetime to 24 hours or 1440 minutes or one day. And the shortest time can be five minutes. So the longest your access tokens can last in Okta are 24 hours. The refresh token is up to unlimited. So let's say we've changed our access tokens up to 24 hours, all right? So why might you want to do that? Well, this is where things start to get a little bit dicey and where it starts to depend on your implementation of both your applications and your APIs and all of your actual business rules about how you want it to work. And that's why I can show you these tools, but I can't, like, necessarily tell you exactly what to do. But I can give you some ideas. Remember that because these are self-encoded tokens, because this token exists now, like, this token, once the client has it, it's out of the hands of the OS server and out of the hands of your API. They have no way to modify this token anymore. So whatever's inside your token, in this case, there isn't much, right? So far, we've only really got a user ID. We do have this subject identifier, which happens to be my email address. We've got the client it was issued to, but not a lot of other information. But whatever's in here is going to, this is what the token represents up until it expires. So let's say, for example, you have configured your token lifetime to be eight hours. What happens if you are, if you want to reject or revoke or sort of, like, undo a token, right? Remember how we have self-encoded tokens where the token, you can validate it without any network traffic, which is cool. That's a useful property. We can go and just look at the signature and say, your API can say, yep, it looks valid. That's great, because it means we can speed things up a lot. However, the problem is, if you are only doing that, then you don't really have a way to handle the case of a token being revoked before it expires. The other way you can validate tokens is actually by going back over the network and asking the OS server, is this token really still valid? Where the OS server can be keeping track of more of that state about, like, whether the client credentials are, our client is still active or things like that. So if you are looking at the two different ways of validating tokens, then the problem is that they can start to disagree, because your JSON web token is essentially a cache. At first, everything looks fine. Both ways of validating tokens agree, but as soon as something changes in the system, like a user revokes the app, or a user is deleted or an app is deleted, then the two ways of validating tokens disagree. Local validation still says it's valid because you can't change the token, which means whatever your token lifetime is, is the window in which these two methods might disagree. Once the token expires, they agree again because your token is expired and the app has to go get a new one. So essentially, you're in this weird position where you don't want to give up local validation because it's useful to speed up your validation code, but you also don't want to, but you then don't want to have access tokens last too long because then you might have a full day before you can actually properly revoke tokens, but then you also don't want to have your access token so short that it ends up creating all this extra network traffic. Because again, remember that let's say you did go back and change your token lifetime to five minutes. That might sound good in theory, but what that actually means in practice is that your OAuth application is only able to use this token for five minutes and then it has to get a new one. And how is it going to get a new one? Well, it's going to either if it doesn't have a refresh token, it has to go send the user through that round trip again, or if it does have a refresh token, it has to go and make a post request with a refresh token. Both of those are kind of quick, but depending on the, depending on the circumstances of like, are you on a mobile network where every network cost, every network call is potentially very risky because it might fail because of the bad mobile conditions or are you, do you have so many applications and users deployed that if you were having all of them refresh tokens every five minutes, you would just, your network would be completely saturated with those refresh calls. So you need to find the right balance between token lifetime and whether or not you're validating tokens by just looking at the token itself. So that's why you get this range, but it's also why octa caps it at a day because octa, I guess it's just made a decision that you shouldn't be working off of cash data for, for more than a day, which gets especially important once we start putting more things into this token. The other part of token lifetime is based on your sort of risk assessment and who the token might be issued to. So for example, you might say that your admin users are a higher risk group because they have permissions to do more things. They have permissions to modify more data, delete more data, things like that. So you may want to be sort of take a, take an approach of more security on the, for that group of users that even if it costs, even as you, even if it has your user experience costs. So even if you do increase the network traffic or do run the risk of the user having to re-authenticate again more often, it might be okay because this group of users has, is a higher risk group. Now, if you had your consumer users using your shopping cart app and they had to log in every day, it'd be very frustrating and they would just stop using the app. You want them to have the best user experience, even if it comes to the cost of security in some cases. So you might give them one day long access tokens and unlimited refresh tokens. And that way it looks like they've logged in once and then they're just always logged in and in practice, what's happening is the app is refreshing the token, but only once a day. So you've gone completely on the other end of the spectrum in terms of whether, whether you're, you know, on the security spectrum there. So that's great. But then you might be like, well, okay, it's great for browsing the catalog, but if they're going to go do a purchase, I'm not really comfortable with an access token that was issued five months ago. And I haven't seen, I haven't actually seen the user at the OAS server recently. I'm not really comfortable doing a purchase with that access token. So that's where you're, again, in this weird position of like, well, how do you deal with that? And that takes us to the next, the next topic, which is custom scopes. So for this use case of like, let's say we're building a shopping cart app, you want the user to, well, actually, you probably want them to browse the catalog without being logged in at all. But let's say you've at some point made them make an account to be able to like bookmark things, like save things to their profile, like favorite items or something. You need an access token for that. And you want that access token to last as long as possible because you don't want them to have to be logging in all the time in order to see it. But then they're ready to go and check out. Then you don't want the checkout API to accept access tokens that have been issued with refresh tokens that may have been first issued months ago. So how can you solve that? There aren't really like ways to find out like the original time the first refresh token was issued, but it doesn't matter. We can do it a different way using scopes. So what we can actually do is we can say, we're going to make a new scope. Let's call it checkout. And the checkout API will only accept access tokens that contain the scope checkout. And then what we can do is create a rule in octa that applies only to that scope. So if I go here and if I say, let's cancel that, if I make a new rule, and I say, actually, we're going to, oh, I don't think I have any scopes yet, but let's say that I would make a scope called checkout, and I'm going to go and make a rule called checkout. And then I'm going to say, actually, you only get access tokens at a last for one hour and same with your refresh token, so that there's no way that an application can reuse a refresh token that's older than an hour. Because now what you've done is if the token contains that scope, because you've got this rule configured, you know the token had to have been issued from a user being in front of the keyboard within the last hour or whatever your policy is here. So let's go do that and see if we can take off that box in the challenge. Oh, I do see that a bunch of you have already skipped ahead and have in fact already figured out how to create a custom scope. But we're going to go through this. Okay, so we've got, we've done this one, add the token lifetime. We've changed the token lifetime. Now we're going to go and do the scope. So again, back to security API, choose the default authorization server and then click scopes. Here we are. We're going to go add a new scope. And for the challenge, we're going to call it developer day, but you could think of this as being the checkout API. We are not going to require user consent for this. Because this is really just for our own internal sort of business logic. So we don't want to bother the user and say, hey, it's okay if the shopping cart uses, you know, is able to complete a purchase. You're like, yeah, that's what I was trying to do. So we don't need to require user consent because we're just using it for our own internal logic. In this case, we don't care about it being included in public metadata. We just want it because it's again, just internal business logic. So we're going to create that. But now what we can do is we can go back to our OAuth client, start over and add that to the request. Start the flow. We can see that it did put the scope in the URL. And now when we continue and go get this access token, and then let's go and look at it here, we got that checkbox. And now we can see that it's in the access token. So now what you can do is when you're writing the API, you would have a rule in somewhere in your API code. And this is where we're getting into now, like, it's going to depend on how you're actually implementing this. But it's your job as the developer of the API to say, this method is the method for the checkout operation. The checkout operation should only work if the access token contains the checkout scope. So you'd write a check to say, does that array contain that value? If not, throw an error message and do not complete the purchase. And then you know that, you know, even if the access token is new, you don't, there's nothing in here that talks about when the first authorization took place, so like, when was that first refresh token issued. And so, but because of this presence of the scope means that it then does last a shorter amount of time. So that's enough for the challenge. But yeah, the sort of larger context of that discussion is now that's created, I can, I can go make a policy. And I can say limit token lifetime for developer day scope. And then we will limit it to, I don't know why I clicked that. We will make this rule happen if the request contains developer day, then we will limit the let's limit it down to 30 minutes and save that rule. Now, I will say that the, so that these get run in order. So we have to put that there. But also it only runs on exact match of the scope. I do kind of wish that worked differently, but it does only work for the exact match, which just means that your OAuth clients and your APIs have to be aware of that. And the client has to request only the developer day scope, no other scopes, start the flow, get the token, and then see how the expiration date is now super short. So this token now contains only the, only the developer day scope and no open scope. And if you had included any other scope in the request, that rule would not have run the token. So we wouldn't be limiting the lifetime. What that means is that your API needs to check for exactly that scope. I need to say is the scope exactly developer day, that way you know that that rule ran. Okay. So that is, that gets us through this one, I believe. Yep, and we can see it here. Oh yeah, extra credit. Let's see how this works. Let's, let's require, let's check that require consent checkbox. So we go back to the scopes and we do require user consent and save that. Let's go back and log in with that scope and visit octa. And now notice that we get interrupted by octa and the user is actually presented with this dialogue. This app would like to access this scope. I didn't put a descriptive sentence in there, but there's a way to actually write a full sentence there that would mean something like, is it okay if this application accesses your photos? Is it okay for this application to modify your photos? And now if I allow, then I get taken back here and the app can get the token. So you can use that for, that's really useful for third party apps, for example, of if primarily that's the, I would say the bulk of the use case. So if your, if your APIs are being used by companies that are not you, if you have third party developers, then that is a, that's when you might want to turn on the consent feature for the scopes that the third party developers might be accessing. But for first party apps, it doesn't really make sense for like, again, for your shopping cart app to ask if it's okay to complete a purchase because that's clearly its purpose and there is no trust issue there because it's all first party. I will say the one first party case that you may find where you do want that consent feature is for high security operations where, as long as it's not confusing to the user, but if your applications are public clients, like mobile apps or single page apps, they don't have the ability to use a client secret, which means your client, you don't really have real client authentication, which means it's theoretically possible for someone to mimic an OAuth flow and possibly even get an access token that should be issued to the real public client, but sort of mimic everything about it and get an access token that's instead issued to the attacker's fake app using the real public client ID. If you are concerned about that case, then you can require the user consent there because the user will be interrupted and it would say, hey, are you actually trying to log into this app? It's trying to do X, Y, and Z, and that might be enough to trigger the user to recognize that something fishy is going on. I will say it's not the most common use case, but it does happen in the case of the sort of high security operations for public clients. Okay. So what is next? Custom claims. So let's talk about some of these custom claims. I don't think I have any slides for these. That's fine. We don't need slides. So custom claims. What we're going to do is try to add more information into the access token. So right now, you can see that there's some information, but really not much more than just which user ID, which client ID it was issued to, the token lifetimes, what OAuth server it's from, and our scopes. Let's say you actually want to start packing more information into there for various reasons. Like in our example, we're going to make a claim in there called favorite color. So if you want to actually pull user profile information and put it into the access token, in case you want to have the access token contain something about the user so that you don't have to look it up, the other really common one that I hear a lot is people wanting to put group information. So groups or roles or whatever you're calling it. So where was I? Let's do groups first. And that's not in the lab, but I'll just show you how to do that anyway. And then we'll go back and do the one for the lab. So again, security API, click on your authorization server. Now we're configuring it. We did talk about scopes. We're going to go move over to the claims tab. So what we're going to do is add a new custom claim, and we're just going to call it group. That's going to be the name of that JSON field included in access tokens. And then, let me make this bigger. I just realized how small that is. It's going to be just groups. And now there is this filter. So because apparently people have a lot of groups sometimes, but you can filter out groups to meet the following conditions. It starts with equals, contains, or regex. I'm going to just, since I don't have any groups on my account yet, I'm just going to say .star and we'll return all groups. And you can make it show up in the access token always or only if certain scopes are requested, which is kind of cool too. But we're just going to do always. And now we should have, for any new access tokens, created, obviously, because we can't go back and change old ones. For any new access tokens created, we should be able to see the group claim. So where am I? Back to the old client, start over. I'm not going to change scopes or anything. Start the flow, continue, exchange the code. Here's the access token. Let's go take a look at what's inside of it. And sure enough, there is a new group. Oh, I do have a group on my account when I was playing with a fake photo API. So this is the list of groups that this user is in. Now, here's where this is, here's where, again, we get to this sort of problem of how you're validating access tokens. Because if your API is looking at this JSON web token, doing the JSON web token signature validation, and then reading the information in here to determine whether or not to run a particular operation, like let's say we're writing an API that's going to be, it's deleting a photo from the library, we only want the photo managers to be able to delete those. So we're only going to run that API that we're only going to perform that operation when we're building the API if the group claim contains that. But again, this token was issued at this time, and it's valid for this long, meaning as long as we're within this window, the user may have been moved out of that group. And that information is not reflected in the token. That's the trick. Does that make sense? I feel like it's more obvious when we're talking about like concrete information inside the token. We've got a group claim saying this user is part of this group. That is a true statement as of this time issued at. As of that date, that was true. However, it may not be true anymore, because if I go and just take myself out of that group, because I can do that, right, I can just go back over to octa be like, let's go to the groups. Here's that group. And then, oh, manage people. How do I do this? Yeah. Um, remove that user, save it. Cool. I'm not in that group anymore. But this access token is still exists, and it's still valid until this date. So that means my API endpoint that's going to be deleting photos will still accept this photo, this access token, for a little while longer. So that's that sort of weird situation you're in where there isn't a good solution to it. That's the problem is there's no clear obvious path. You just need to be aware that whatever your token lifetime is, is that window and act accordingly. Now, if you do care about knowing the most up to date information about this user, you can go and use the access token to fetch information about the user and go back and ask octa what groups this user is this user in, and then it'll tell you the current information. So the, um, or you can just tweak your token lifetimes so that you don't care about that sort of wiggle room. Okay, now let's go back and do this one, uh, here to actually go get that checkbox in the exercise to add a custom claim, navigate back. Yeah, we did that go to the claims tab. We're going to add a new claim and call it favorite color this time. So we're going to go back security, uh, API, go to the authorization server, go to claims, add a claim, call it favorite color, and it'll go into our access tokens. It'll go into, uh, it's going to be an expression this time. Now this is a rabbit hole. We're not going to go down, uh, but it's very cool. Basically, there is this thing called expression language, and this is a way to pull attributes from your user directories into your access tokens. So in real life, you would read the docs here, go figure out like what attributes are you trying to pull? What are they called? How do you access them? Like there's all these examples of, you know, of stuff. Um, so, oh, we can come back to this one in a second. This is cool. So the, we're going to make an expression, um, and we're just going to set it to a string because I don't want to go and actually configure a directory right now. So I'm just going to say favorite color. I probably need to make sure that is a valid JSON string. Um, it's just a hard coded value. So that's not very practical in real life. You would go and pull out of a directory, but this will work. Um, now again, because it applies to any scopes, all of our access tokens that are created from now on will contain that, that custom claim. So go back here, start the flow, get a new access token or get a new authorization code, exchange it for an access token. Let's see what's in this one. And there's our group. Notice that this one, now I'm taken out of that other group and there's a new favorite color. Um, yeah. So if I drop this into this website, we should take that last box. Oh, my token lifetime went back down because I, uh, because I requested only the developer day scope. If I add back the open ID, it'll run our default rule instead of our custom rule. And yeah, there's our long access token, uh, full day and paste this in. Cool. And I completed it. And then it's going to go ask me to put in my shipping address so I can send myself a book, but I've already got them on my bookshelf. So I'm not going to do that. Uh, hopefully it looks like some of you have already done that. Oh yeah. Cool. Awesome. Lots of, lots of folks. Yeah, let's talk about API gateways really quick because we've got, uh, we've still got some time. So this is a, uh, this is a possible way to get around, um, the sort of weird cases of handling, um, handling token validation differences and the fact that you are essentially working off of cache data when you are looking at the JSON web token contents. So in, um, in a larger, in a larger system that is, uh, you know, much more beyond just one machine running an API somewhere, uh, API gateways start to look really appealing for a number of reasons, right? You put an API gateway out in front on the internet and that's the one handling requests from the public. It's handling your valid tokens. It's handling your, um, expired tokens. It's, you know, getting requests with, from attackers or just junk. So it's handling all sorts of, uh, of stuff. And it's, because it's handling everything, you need it to respond extremely quickly. So what we can do for this is we can say the gateway is going to do only local validation, local validation being the fast look at the JSON web token, is it valid? And, uh, what that means is that we can very quickly throw away the stuff that fails fast validation. So the gateway will pass through requests that are both valid tokens as well as, um, these revoked tokens or tokens that maybe may have stale data now. So we just, we know that that is happening because it's only doing the local validation. So it's possible that the data, that the access tokens, if you've got a bunch of custom claims in there that they are actually, uh, potentially stale data because they were issued longer ago than the data changed. So, okay, we've done a first sort of filter. Um, the gateway is then going to send these requests, uh, and possibly the access tokens and a header also, uh, back to your actual backend APIs. Now, this is where it gets interesting. Your backend APIs get to the side whether it, whether they care about whether or not they're acting on stale data. And in some cases the answer is they don't care. So for example, your, um, a, uh, a customer API that's going to return the user's current, uh, rewards points balance. It's just sending, it's returning back a number. The number does not represent the user. It is just a number on their account. Um, it's not sensitive data. It's not identifiable. Uh, it doesn't change very often. It probably doesn't even change within the window of whatever your access token lifetime is, at least not that often, which means if that method doesn't do any further validation, you're probably fine because there's no real information, uh, extra information leaked. Whereas it's, that's a completely different story from like a billing API. If you have a, um, a, uh, like a, a billing address or something in the access token, that's actually a really terrible idea. Don't do that. Um, but if you had a user, uh, that had authorized an application and then it goes, that application goes to make a requested billing API, but then the user revokes that app or the user is deactivated or something, the access token still looks valid. The billing API definitely does not want to charge a credit card based on information that might be stale. So it's those particular cases that you can either, again, use scopes like we talked about to, uh, tweak the, tweak the, um, token lifetime rules and the policies, or you can actually go and in those particular methods, go back and actually ask the OAuth server, go do a introspection call, go actually look up user information in a database or whatever it is that does take extra time, but that's able to then revoke or to, to see that that token has actually been revoked or changed. And that's how you can kind of split the difference there, because again, what you've done is you've let the gateway do the hard work of, or not the hard work, but it's doing the bulk of the work of, it's that first filter on the outside where it's rejecting stuff really quickly, but very, uh, a lot of things very quickly. And then the, on the other end of the funnel, you've got a much smaller number of requests being validated slower. So you've kind of balanced it out that way. I see a couple of other, uh, questions. The, uh, why does the subject in ID tokens contain the octa user ID but subject in access tokens is the login value that contains the UID in its own field? Um, it's kind of a complicated answer. Let me think. So subject in open ID connect in the ID token is defined in the open ID connect spec. So if we go back and take a look at our two tokens that we got, let's pretend we're the application. We're looking at the ID token and we, uh, look at the claims inside of it. The subject is this opaque identifier of the user, right? It's not the user's email address. And the reason it's not the user's email address is because an email address is not a stable identifier for a user. A user can change their email address. You can usually go into your account in websites and, uh, change your email address on your account, right? You kind of need to be able to do that. So it's not stable. It's not guaranteed to be stable for that user account. So what octa does instead for ID tokens, where the application is assuming that subject is a stable user identifier, the, uh, instead it uses the internal ID of the user. And that's what a user for the subject claim. That's because applications will be, um, expected, are, are expecting to rely on this as a consistent identifier for a particular user account. Now access tokens are a different story. And this is where it gets a little bit messy. And I'm sorry, I don't have a better answer for this. Let's take a look at this claim. This claim actually is configured on my account. Now I can't delete it, but I think, I think this is the default value, but I'm not actually sure if I have changed this before. You might notice that it's, uh, it's actually an expression. It's saying if there is no, or if there is a value for the app user, then we're going to use the app user user name, otherwise client ID, because access tokens issued for the client credentials grant also have a subject, but there is no user. So in that case, it's actually the app's client ID. So this is weird. And I, uh, question how useful this actually is. I would, um, I don't like the idea of not being sure whether this is like a user identifier or a client ID. So I would be inclined to actually just completely ignore this claim personally, because these ones are the two that octa defines and I can't modify it. It's like, this is something that's built into octa. That is the client ID and that is the user ID. And let's see, this should match the subject in the ID token. Let's see if that is true. If it doesn't, I'm going to be, uh, annoyed. So if we look at the subject, it's, let's see if I can just paste it in. Yeah, that looks the same. So the subject in the ID token is what is returned in the UID claim of the access token. So again, that's the stable identifier. That's not going to change if the user changes their email address on the account. If your APIs are relying on this claim and it's the, uh, what is this user username, which happens to be an email address in my case. Again, I don't remember exactly why it, I can't remember if I customize that or not. But if your API relies on this to identify the user, as soon as they change their email address, your API is thinking it's a different user, which is not good. That's why I would rather rely on this claim. So that's the deal there. And then the sort of complicated history is that um, there is a spec now called um, let's see, oh, specs, json web token profile for access tokens. It is very, very nearly complete. This spec defines a format for json web token access tokens. And it actually says, if you're going to use json web tokens for access tokens, here's the best way to do it. Here's what you should put in the header. Here's what you should put in the structure. And so here's where it says what the subject should be, which is it should correspond to the subject identifier of the resource owner, which should be that opaque ID. Or client ID, in the case there's, where there's no resource owner, but this is what, this is what's kind of annoying. Notice how that client ID is spelled out and there is no UID. That's because um, octa actually built this way before that spec existed and helped influence that spec, which means the spec was done after octa's implementation was done. And I don't know if like, there's not a good sort of path to clean that up. I could see, I could imagine a way to sort of have a migration path off of that, but that's, that's the sort of mess of the real world of like, you don't want specs to be created in a vacuum, because then you end up with bad specs, but that means you have to base specs on actual implementations. But then if people disagree about a particular implementation, like what a claim should be called, then you end up with this sort of split world. So long, long story, not important. But you'll notice that there are slight differences between this and Auth0, because both companies decided independently to use JSON Web tokens as access tokens and then made their own decisions about what to put in them and what these things should be called, and then later worked on a standard together. And that standard is now nearly final, but that means that there are some implementations that are slightly different. Okay. Eugene says, in Auth0, there's a, from the rule you can point to use MFA, which will be U2F. So, okay. Eugene was thinking about Auth0. So yeah, I don't know about, about the case for, in Octa. Cool. Okay. Let me see how everybody's doing with the exercise. This is great. That's a lot of people who finished. Okay. I see two people who have not finished yet. You still have 45 minutes. All of the instructions are in that doc linked in the chat as well as on the page. So you should be able to finish in time. But I think that was about, about all I want to share with you today. So, yeah, unless you have other questions, we're going to go ahead and wrap us up ever so slightly early because I think I don't know how much more I can talk today, frankly. It's been a fun day. So yeah. Again, if you do want to use this tool, this is available for you to try at any point. You can use it with Octa or Auth0 or whatever. Example-app.com slash client. Feel free to use that if you're testing things out. Again, don't use it in production because it's taking your client secret and all that stuff, but it's a good testing tool. Can I ship books to India? Yeah, I can. I can do that. I don't know how long it will take to get there, but I definitely can do that. So, yeah, let's wrap this up with a couple of links. I do, I would appreciate if everybody here would take this, fill out this survey. I'll drop that in the chat. Survey about all the sessions today. I would love to know how many you came to, but feel free to just answer these few questions. If you have any notes in here, free form text box at the end to let me know your thoughts. There's a lot of good hopefully, hopefully we get some good feedback on this. I hope this was a fun day for everybody. As far as the where to go to learn more things, oauth.com is the electronic version of my book, so it's like the web-based version. Everything is a web, every chapter is a web page. You can search it in book market. It's very useful. It's available there for free. Oh, another tool, which we didn't use today. It's the OAuth Playground. It is a simulation of all the different flows. You can see requests and responses for all the different flows. Everything is fake in it. It doesn't talk to any real services, but it's a good way to see what's going on on the wire. I pulled up OAuth.net a second ago, which is the community website for OAuth. That is where you can go and find links to articles, books, blog posts, videos, code libraries, all sorts of good stuff on that site. It is also open source if you ever want to change anything, where was I? There's a link at the bottom of every page, and you can just go and edit this page on GitHub. Please feel free to suggest things. The OAuth developer blog and the OAuth zero blog are great resources as well. Lots of good blog posts there. Samples of how to get started in different frameworks and languages, also sort of general conceptual overviews of things like this. We have both OAuth zero and OAuth have great YouTube channels. A lot of good content on those. I host the live Q&A session. We are monthly-ish, where we talk about what's new in the world of OAuth, talk about what's happened in the standard space, or answer questions from the chat. Yeah, a lot of fun. You are all going to, if you finish the exercise, if I got your shipping address in that form, I'm going to send you a real version of the book. The way this works is it's shipped from the printer directly, so I don't actually hand-pack all the envelopes. It means you can get it faster, usually, because it means a local printer is printing it, instead of me shipping one all the way across the world. If you would like a deeper dive on any of this stuff, I also have a video course that goes into a lot of this stuff. You've got a sneak peek of some of the exercises today. The OAuth.school website is what I use in the course to walk through those exercises, but it goes into more of the details in more of the different flows and different topics. It's a great resource as well, and it's at that link on the screen. Yeah, with that, we'll wrap it up there. Thanks everybody for joining. That was a blast, and thanks for coming to Developer Day. Okay, thanks. That was fun, and I am out. I will see you all later. Thanks.