 Let's go ahead and get started. Thank you all for being here. So the first thing I want to start with is a bit of background on OAuth and OpenE Connect. I want to talk about some of the history, some of what OAuth is, kind of set the stage for that. And then we'll get into the how it works part of it. So if you haven't yet made your auto developer account, this is a great time to do that while I am giving this background information. So the spec, the OAuth spec is not a great way to learn this stuff, it turns out. The spec is more of like a reference guide and you really have to know how to read specs before it's even useful. There's a lot of terminology in there that's pretty confusing and it takes a while to understand how these things work. OAuth is also not even just one spec. OAuth is quite a lot of specs all put together and some of them are even made by different groups and different organizations. So it's a pretty big mess to try to sort through on your own. And that's what I'm here to help sort of help with is I want to give you a path to find your way through this mess of a maze. So I want to go back in time first and talk about why we have OAuth to talk about originally the problems that it solved. And I did mention this a little bit in the video in my session yesterday at the Developer Day Conference Day. That video will be available very shortly on YouTube. So if you do want to go watch that back later, that'll be on the OctaDeveloper YouTube. But this used to be a very common pattern on the internet which was how things worked before we had OAuth. The application, a third party application like Yelp would launch and it would say, hey, are any of your friends already using Yelp? And to find that out, we're going to say, is the application would ask you for your password to your email and then it would go sort of log in as you and go download your contacts and see if that would, you see if any of your friends were already using the app, right? So it's not a great solution because it means that what you're doing is you're basically giving the credentials to your account to some random application like Yelp or Facebook, everybody was doing it. And this has many problems, right? I don't want to go around giving my login to my email to random apps because it means it can do anything as me and I don't necessarily trust it that it's going to do only what it's promising. It's saying it's going to only ask for my contacts but there's nothing actually stopping it from accessing the actual email on my account. So this is really the sort of origin of what OAuth was trying to solve which is how do we let applications and it started as this third party app access of Yelp is trying to access data in Google or last step I'm trying to access data in Spotify, Buffer trying to post into your Twitter account, whatever that might be, you know, third party, one company's application talking to a different company's API. And that's really how OAuth started because it was clear that we didn't want to share passwords with these third party applications. That kind of led to this use case of these sort of sign in with X buttons and this was not necessarily the original goal of OAuth. This was not what OAuth was actually intending to solve but people ended up repurposing it for this because they saw a sort of way to kind of make that work sort of. And we'll talk about the sort of in more detail later. So what's interesting is that there's actually nothing in OAuth to talk about who the user is that was all added later by OpenID Connect. So again, getting back to the OAuth part, I like to think of it as this analogy of checking into a hotel where you go to the front desk, you show that person at the front desk, your ID and credit card and they give you back this hotel key and then you go to the door and you swipe the key on the door and the door lets you in. Now, this is exactly analogous to OAuth and what's interesting about this is that the door doesn't need to know who you are. The door doesn't actually care about the identity of the user who's going to be using the room. The door just cares about whether the key card is authorized and I want you to remember that when we talk about OAuth access tokens. Access tokens don't represent that a user logged into something. Access tokens represent that the application is authorized to access data. So it's a slightly different problem and I know it's a little bit confusing but OpenID Connect is the other half of that picture. OpenID Connect is explicitly a way to say this user logged into this app at this time and that is where the user information is provided in through OpenID Connect. The good news is OpenID Connect is built on top of OAuth so actually once we learn the foundations of OAuth, OpenID Connect is not a lot of extra stuff to add on top. So we're gonna start with how OAuth works by actually walking through a flow and then we will also talk a little bit about OpenID Connect if we have time for that. So the first thing I want to do is I wanna talk about some of the terms you will find in the flows and as you are going through and using this stuff. These are the roles in OAuth. So we have users who are gonna be using an application through some sort of device, a phone, a browser, right? And then eventually that application is gonna make requests over to the API. Now the API is in OAuth terms, it's actually called the resource server and these things have terms in OAuth that are confusing compared to what you would say in a conversation but there is a good reason for it to find that way but not really important for our purposes. The thing that's missing from this picture is the thing that's going to be actually creating those access tokens, handing them out, validating users, getting users to log in, all that stuff around the sort of user management. That is where that's the job of the OAuth server or the authorization server. So this is the complete picture, we have users who are called resource owners in the spec using devices or a user agent to access an application, that application's the one's trying to get the access token because it's trying to get data from the API. Now what we're gonna talk about for the most part in this workshop, in this lab today is how these two pieces talk to each other, how the application coordinates with the OAuth server to both to sign the user in, get the access token and we're not really gonna deal with the API yet because that is a job for the afternoon. So we are ready to start this and to sort of set things up because I wanna make sure you have a chance to actually try this stuff out. We're gonna dive in and I'm going to do this first part of this workshop live with you and try to make sure that we have everybody keeping up. So back to the, back to, if you scroll down you'll notice there's a link to this document preparing for the exercises and I will also drop a link to this in the chat room but it is down at the bottom of the page as well. This is what we're gonna walk through first and I'm just going to go through it live with you right now and please do try to follow along and we will, what we're gonna do right now is basically set things up. We're gonna be able to set up the Octa account, set up the OAuth server in order to be able to use it for the next exercise where we're gonna actually do the OAuth flow. And I've seen some questions in the chat. Got an Octa account to watch this presentation, got an Octa account to see this thread where else do I need to get an account? That should be it Eugene. The Octa account is what you'll need in order to follow along with the steps I'm going to do. The Auth0 account, it's not, don't really think about it as an Auth0 account, it's just how you got into the chat room. You don't actually get any permissions to do anything in Auth0 other than just joining that chat room. That's an organization I set up as if I were a customer of Auth0 in order to get people signed into the chat. Okay, so, and then there was another question. Oh, the slide deck. I will post the slides afterwards, yeah. But the PDF that we're looking at right now or the doc that we're looking at right now is what you'll need to follow along with the exercise. So, we are gonna go ahead and get started. I'm gonna make this bigger so that I don't, there we go. Step one is getting your Auth0 developer account. So, this is, hopefully you've had a chance to do this ahead of time because this does require sending an email, clicking on the link from the email so it takes a minute, but it's not that long of a process anyway. Once you are logged into your Auth0 developer account, we're ready to actually configure it. I should also mention that for the purposes of this exercise as well as the one in the afternoon, generally anytime you're doing these sort of trial things where you're following somebody else's instructions, it's usually a good idea to not do that in your own production environments. Please do it in a development environment. That way, you don't risk messing anything up and don't have any sort of security issues around that. So, I have created my org. It is this, I have a custom URL, mine yours will end up with just some numbers on it. But, I'm ready to set this, set up my octa org for completing the exercises. I'm gonna give this split screen so I can don't have to switch back and forth all the time. If you are looking at it in a smaller window, the navigation bar on the side has collapsed. I've seen some people get confused about that and think, ask why they can't find it. So, that is where it is. It's in that little collapsible hamburger. So, first thing you wanna do is go to security and go to API and this is where you're gonna sort of set up your OAuth server and tell octa how you want it to work. There should be only one by default. It'll have some random numbers on it. Maybe I should just go over to my account that has the random numbers. Let me see if I remember what account that is. Because, maybe this one will work. Yeah, great, okay. Get rid of that one. I'll bring this one back. Okay, this is more like what you're gonna end up with on your account. Security, API, default. I have one OAuth server. It is just the default OAuth server. That's how it works at the beginning. So, this is the page that talks about like, okay, here's my server. Here's the audience for it. Here is the issuer. Now, the issuer is this an important idea of this is the identifier of the server. So, this does a couple of things. It's, we're gonna need it in order to verify things in OpenD Connector later, but it also is useful for telling the application, the OAuth app, how to find the various endpoints in the server. So, if you notice this metadata URL down at the bottom, it's actually the issuer URL with this extra thing tacked onto it here. So, and if you click that, this contains information about the server. Like, what things are supported and these URLs. These are the URLs we're gonna need later. So, let's just keep that in mind. That's how you find the information about your OAuth server. So, we're gonna go copy this and write it down because we need it later. So, I'm just actually gonna open up text editor. I just like give myself a little scratch pad. Okay, make that plain text. So, here I just have a little scratch pad so I can keep track of this stuff issuer URL. Now, what we have to do, in order to sort of do and OAuth flows, we actually will need to ask for a scope. I'm gonna talk about scoping a little bit. For now, what we're going to do is just go ahead and create one. So, I'm gonna go to the scopes tab and it looks like I have a couple of test ones and this one, delete these, okay. So, we're gonna go add a new scope and we're just gonna call it developer day and click this box include in public metadata. So, what this is gonna do is gonna give the app a scope that it can request. At this point, you might notice there's also a bunch of other scopes in here, all the OpenID connect scopes. These are the ones that kind of are shipped by default and these will tell the OAuth server or these are built into the OAuth server so that the app can request things like the user's profile information or the user's email address. We'll get a chance to try all that out. Okay, once you've done that, you're ready to sort of check your work. So, what you can do is go to this website, OAuth.school and click on the getting started, which I will drop this into the chat again. So, there's the introduction exercise. What this is going to do, this is a tool for this workshop that is going to let you check your work and see how far, see if you've done things correctly. So, what we can do is if we've set things up properly, we should be able to get green check marks on this step. So, I'm gonna go back to my OAuth server and copy that issue or URL, paste it in here and cross my fingers. Okay, so, what it did is it verified that there was a custom scope that I added and now it's asking me to find my authorization endpoint and token endpoint. So, these two are the URLs that the OAuth application is going to send the user off to or go get access tokens from. And we'll walk through the flows in a second where you'll see how these things are used. The authorization endpoint, think of that as the one that the user interacts with and the token endpoint is one the application interacts with. So, how can you find these? Well, it turns out that is part of the OAuth metadata. So, if you go back to this metadata link, which again I found from the issue or URL down here, go find the metadata link. It is actually two URLs up here, authorization endpoint and token endpoint. So, we're gonna copy that, paste it there. We're gonna copy the token endpoint and paste it there and we're gonna check the work and I have in fact completed the exercise. Okay, so, if you are getting an error before this, the error is probably because of the scope step. I kind of went quickly through that. Let me go through this again. If you go to scopes, add a custom scope, you do have to check the box, include in public metadata. That's important because that's how this tool can actually check that you've created the scope. What that actually does is if you go back to this metadata document, see how there's a list of scopes supported? If that public metadata box is not checked, your custom scope won't appear in this list. So, it contains all the opening connect scopes by default, I've created my custom scope and then put it in this, put it in the metadata so that the tool that's checking your work can actually see it there. So, that's enough to complete the exercise, but let's go back and talk about what's going on in some of these things, because I kind of just threw a bunch of stuff at you really fast. So, let's go back and talk about, let's start with scopes. So, scopes are something that are mainly used for, I have the wrong slide deck, that's what's going on. So, scopes are what a, from the application's point of view as the app developer, you're not really gonna be worrying about designing scopes. You're pretty much gonna say, you're gonna say, oh, I'm trying to use this API and it's telling me that I have to request a certain scope if I'm gonna be using these kinds of endpoints. So, you might see that on, let's actually just go look at the GitHub docs. So, GitHub, OAuth scopes, and if you look at this, GitHub has a long list of scopes. So, notice that they are sort of, they give access to different groups of things. So, there's like the repo scope. If you do an OAuth exchange with GitHub and you get an access token and you don't request any scopes, it won't give you access to any of the actual API endpoints. So, if you want to be able to read and write code in a repository, then you'll need to request that scope and then the access token will contain that scope. So, these are all defined by the, sort of defined by the OAuth server and as you're developing your APIs, you'll be responsible for creating these and deciding how they work. And we will give that a shot in this afternoon in more detail. But for now, as an app developer, just know that you need to go and figure out what scope you need to request before you can actually go and use an, use an API endpoint. Okay, so that's scope. Let's talk about the endpoints, the authorization endpoint and the token endpoint. So, the two endpoints are, there's two parts of the OAuth flow generally. There's the part where, go back to this picture. There's the part where the application says, hey, I'm trying to get someone to log in and then after they do and it gets them back to the app, the app is ready to say, hey, I want access tokens now. So, what this really means is it's the, the OAuth server has two endpoints, that it has the authorization endpoint, which is sometimes at slash authorize, but depends on the server and there's slash token. So, this means the, this application is going to first redirect users to the authorization endpoint and then it's going to make a post request to the token endpoint. So, let's go walk through, let's go walk through one of the flows step by step in slide form before we actually go and try this by hand. Okay, so we're going to start with the authorization code flow with Pixi. So, okay, authorization code flow you've probably heard of, that is the sort of default normal flow, whatever you want to call it. And that is, if you, if you're doing an OAuth flow from most kinds of apps, you'll end up doing the authorization code flow. The Pixi is a extension, it's one of those puzzles in the maze of extension to OAuth that talks about it adds some extra security to protect the flow. We're going to look at the whole flow, including Pixi step by step right now before we actually try this on our own. So, across the top we have our roles that we've talked about of, you know, the users interacting with this application. And I do want to just again reiterate, most OAuth clients will use this flow. Mobile apps, single page apps, web server based apps, those are all possible to use this flow with no changes to the flow. There will obviously be differences in how they will do the different parts in terms of where they're going to be storing things, but the flows are actually the same. So it is auth code flow plus Pixi. So this starts off with the user saying, I'm trying to use the app, that's them clicking the login button. So the user says, great, trying to use this app, here we go. The app says, hang on, we're going to generate a new secret for this flow and calculate the hash of it. And this is the first part of Pixi. So what this is doing is basically the app is creating a random string and then the hash is a one way operation. So for example, if I told you, think of 10 random numbers writing down a piece of paper, keep that secret, but add them all up and tell me what they end up to. I would not be able to tell you the 10 numbers on your piece of paper because it's a one way operation. Now in practice, we use better hashing algorithms than that, but same idea. The point is that even if somebody had the hash, they won't be able to reverse engineer it. So okay, the point here is that the app has something secret that nobody else knows right now. So the app then tells the browser to go to the OAuth server. Go to the OAuth server so that I can get the user to log in. This is the first message that the app is sending to the OAuth server. So this is really all it's doing is just building a URL, telling the browser to go to that URL and then lands at the user will land at the OAuth server. So this is not something that the application the application is not talking to Okta directly talking to the OAuth server yet. The application told the browser to go talk to Okta. This is where the user logs in. If you've configured the consent screen, they will get a prompt to approve the request. And then instead of returning an access token, the OAuth server says, hey, here's this temporary code for the app. And again, this is not returning directly to the app. This is being sent from Okta through the browser to the app. Now we can finish the flow. So this first one is the authorization endpoint. That's the authorize stage. Then the app can talk directly to the OAuth server to the token endpoint and say, hey, here's this temporary code I got. And so that you know that this is the same piece of software that started the flow, here's also that secret that matches that. Please give me a token. The OAuth server can calculate the hash of that secret itself because it's a one-way operation so you can repeat the operation, but you can't undo it. And then what this does is it lets the OAuth server know that, so here's that second request. This one is to the token endpoint. So what it does is it lets the OAuth server know that the same piece of software made the request, started the request to the authorization endpoint and is the same one talking to the token endpoint. And now the app has the access token and the flow is done and we can move on and the app can go and use the API. So this, I often hear people ask, why is there this extra step, right? Why do we have this temporary code? Why do we need that? Why can't we just send the token back directly? And the key thing, the key reason for that is because there isn't a direct link between the application and the OAuth server at this stage. There isn't a direct link and instead what there is is a, is the app is talking to the OAuth server through the browser. That is what we call the front channel. So I wanna talk about this really quick. The back channel is the sort of normal way of what you think of when two pieces of software talk to each other over the internet. It is a post request or a get request actually. And it is an HTTP request that covers both of them. It is, an OAuth has to be sent over HTTPS, otherwise there's a lot of problems. But the point is that it is an HTTP client talking to an HTTP server. This gives you a lot of very useful properties like the request can't be tampered with, you know where it's from, you know who got sent to, you know it wasn't modified in transit. The front channel is when two pieces of software talk to each other by using the address bar of a browser. So that is, there is no longer a direct link between the two pieces of software. So I like to think of the back channel as hand delivering a message where you can walk up to somebody, give them something, you can see who they are, they can see who you are, you can see that nobody came in and stole it out of the middle. Sending data via the front channel is more like putting your message in an envelope and sending it in the mail, where you've handed it off to somebody else to deliver and then it will hopefully make it there but maybe it may or may not, you don't know. You've lost the visibility because you've handed your message off to somebody else to deliver. So that's the difference. In our flow, in the sequence we just talked about, what we've done is we've used the front channel for this whole first half of the flow. We've used the front channel to have the OAuth client start the flow by directing the browser to the OAuth server. The OAuth server then sends that temporary code back through the front channel. Now, the problem with the front channel again is you've lost visibility in terms of whether you know the message was sent or received. So if you've sent a message in the mail, you don't know if it made it there. And if you receive a letter in the mail, you don't know who it's from, you can't prove it. And that's the problem. So we have up until this part of the flow where we're just at the temporary code issue point, we don't actually know if there's been a hack yet. We can't tell if there's been a problem. So the OAuth server's issued this temporary code, it hopefully landed at the right app, it may not have. So we use the back channel to sort of fix that up, plug it up using that temporary secret that I made up at the beginning of the flow. Okay, that's enough diagrams. Let's try this stuff out and actually see how it works. So for this one, I'm hoping people got a chance to finish the getting started exercise. Let me know what I'm gonna do. Actually, what I'm gonna do, I'm gonna put a message in the chat. I'm gonna say, I'm gonna put a message and say click this reaction if you have finished the exercise. So have you finished the getting started exercise, choose a reaction and go ahead and click the, let's see, check for yes. And where's that red X? There we go. Okay, got a bunch of people who are good to go. Fantastic. So let's go ahead and yeah, okay, we finished that. Close that one. So here is the other link. I'll drop this in the chat and should be able to load that up. I should make sure it's also on the webpage. So, okay, we're going to, why is it so narrow? There we go, about this, okay. Now it's on the website. So what we're gonna do is walk through a complete OAuth flow and do what we just talked about in that sequence diagram by hand. Now I do wanna caveat this with, most of the time you are writing software to do this and you're not going to be doing OAuth flows by hand. The point of this exercise is to show you actually what the software is doing under the hood. So most of the time you're gonna be doing, you're going to be grabbing a library that implements OAuth or implements specifically a provider like Octa or Auth0, dropping that into your application and magically everything works, hopefully. That's the idea with the library and that's great and definitely should do that if the library is available. If there is no library available for your particular framework or language or whatever that is or if you are trying to create one of these libraries, then that's really, that's when you're gonna need to know exactly the step by step and the low level. So that's what we're gonna do today and we're going to do it without writing any code because I don't want to, I don't want you to have to be learning some environment or language in order to follow along with the concepts because there's actually not that much going on when it actually comes down to it. So the goal here is to show you at the lowest level what's happening when you're doing one of these OAuth flows. And hopefully that will give you an idea of when you're looking at a library, give you an idea of what it's doing and how it works so that you can better troubleshoot errors because I know from experience that a lot of times once you encounter errors with these libraries, it's often just like you have no idea how to fix it because you have no idea what's going on under the hood. So we're gonna hopefully shed some light on that here. Okay, so I'm gonna go back to here. If this website doesn't store anything like in its server, so if you've closed the tab, it may have forgotten you're getting started progress. So make sure you have a checkbox there before you continue. And for people who have joined late, let me draw that link in again. So we're gonna do OAuth for web applications next. And you might notice there's a bunch of other ones here as well. It turns out that there's actually not a lot of differences between these two, so don't worry too much about it. So okay, there are, again, basically two stages in the OAuth flow. There's the app decides it's gonna start the flow so it has to create a URL to send the user to. And then it's gonna wait for the user to come back to the app and it's gonna go and try to get an access token. So we're gonna do those two stages here. Okay, make sure you've started the getting, you've made sure you've finished the getting started exercise because you need those things we wrote down first. And I've got my little notes here as a scope. I created what's called developer days. I'll just write that down so I have it handy. Next thing we need to do is go and create an application in Okta. So we're gonna go back to the dashboard, open up the side menu, click on applications. Click on applications again. And now we can go and create an app. Looks like I already have a few in here so I'm gonna delete these so that we don't get confused. Okay, so I'm gonna go click on create app integration. From this pop-up, I'm gonna choose open ID connect. Again, remember how I mentioned that open ID connect is built on top of OAuth? Well, most of the time the app does wanna know about who the user is so most of the time we actually do wanna do an open ID connect flow as well but you can click that and then still do plain OAuth if you want. For this exercise, we're gonna say that we're building a web application. So that's anytime the app is running in server side code. So go Java, ASP, Node, PHP. If you were building a single page application that's going to be running in the browser, then you would choose this option and that's going to set a bunch of different settings internally in Okta like setup, cross origin, resource sharing policies, things like that. If you're building a native application which counts both apps running in a desktop environment as well as mobile, you would choose that option and that also applies. Notice that there's this example of React Native because it is also possible that your native app might be written in JavaScript but if it's running in a desktop environment that's the important part. So it's where is the app running? So for this purpose we're gonna say it's a web server based application. We're obviously not going to actually put it on a web server but we're just gonna see how this works. Okay, next we have to give it a name. The default name is fine, I'll just leave that alone. There's other settings in here like a logo, sure. Notice that there's a bunch of different grant types. We've only looked at the authorization code grant type right now because that's the most important one but if we do want to talk about refresh tokens later we'll have to come back and check that box. So okay, the important setting to change here is the redirect URL. This is the list of URLs that Okta is allowed to send the user back to after they sign in. So the flow again is the user's at the application, they click a button, they get sent to Okta, now their browser is on Okta, they finish logging in, they have to get sent back to the application, that's the redirect URL. There's a lot of sneaky hacks that are possible if there is not an explicit list of URLs here to protect the user. So if you don't have a list of these and Okta would send the user back to anywhere, it becomes very easy for attackers to steal things and confuse the system. So we're gonna put in this link which is example app.com slash redirect, example hyphen app.com slash redirect. That is a website I've created to help with this exercise. So it's in the document, copy it out of there. This is when you're ready to actually go and build write code then you would obviously use the URL at which your app is running. And you can add multiple which is useful for example if you are doing, if you wanna use the same application for development or testing or you're testing on localhost and you wanna test on a development server, things like that, but generally you'll probably end up having just one in production. And the rest of this, oh we do need to check this box which is who is allowed to use the app? Just allow everybody, it signs it to that group and then anybody in your org can use it. There's probably only one user in your org right now because it was a brand new org. So we'll check that box. Okay, now we have registered the app. What this does is it gives the app its own identity in the OAuth server. So we are able to now have a record of, for example, this user logged into this app or we can configure policies based on the application like who is allowed to use it or how long access open should last for particular apps and things like that. The app needs its own identity. The app in this case also has its own password. That's what, a client's secret is basically the app's password. It's how the OAuth server can authenticate this application when it's making requests in the back channel. So we're gonna copy these down here because we're gonna need these later. So client ID and then client secret. Wow, I can't type today. Client secret. And I think that's all we care about right now. Great. So with your credentials ready, you are ready to start the flow. Now we're gonna start putting pieces together. So to start the flow, we basically need to create a button on a webpage that the user can click to go and log in. That button needs to send the user to the OAuth server. Alyssa asks, what should we select for controlled access again? Was that what that was called? Oh, it's only in the create flow. So if I go back to create app integration, web application, assign. Oh, I just, wow, I've never read that label before. Just choose everybody. If you don't do that, you'll get an error when you try to log in. So just make sure it's sent to everybody. Okay, so that's created. What we need to do next is craft this URL. The URL is where we're gonna send the user to. So we need to send the user to the authorization endpoint. Remember, the authorization endpoint is the one that the user interacts with. The token endpoint is the one that the application interacts with. That's front channel versus back channel. So we need to find the authorization endpoint. How do we do that? It was here in this metadata. So again, to find the metadata link, you go to security, API, click on your OAuth server, and the metadata link is here. This is also possible for an application to find programmatically because you can take the issuer URL and add on this path, which is in a spec, and then you can find that link. So the metadata link looks like this, and here is the authorization endpoint. So I'm just gonna copy that, put it down here, and we're gonna start building the authorization URL. Okay, before we do the, before we do the pixie bits, let's create the rest of this. And I'll talk about these parameters in this document. The authorization URL, we need to, the app is basically telling the OAuth server what to do, like what it's trying to do. So we're saying response type is code, which is, we're doing the auth code flow. And then we say, which app is making this request? That's client ID. We can copy that. We need to tell the OAuth server where to send the user back to. So we include that redirect URI, which is, I have it in this tab here. Redirect URI. And what else is in here? Scope. We need to request some sort of scope. For now, we're just gonna request developer day. And then, because we created that up at the beginning, we need a random string called state. And for this, I can just type in some random numbers. And now we need to add the pixie parameters. Pixie parameters are code challenge and code verifier. Let's talk about what those are. I, again, created a helpful tool for you, but you're welcome to do this in any, in code or in any language you want. Copy that link, there we go. So exampleapp.com slash pixie. And what this is, is a, it's basically a JavaScript implementation of the pixie functions that you need in order for it to work. So we've got two functions. We've got a random string generator, and we've got the hash function. And if you actually go view source of the page, you can see it. It's down here. So here's the generate random string in JavaScript. Here is a shot 256 hash function in JavaScript. But you can use this to get what you need. You need a random string. We can just generate them all day long. It's not storing anything. It's just doing this on the page. It's just for troubleshooting. And then once you have your random string, which is called the code verifier, you can calculate the hash of that, which will appear down here. Now, if you are trying to write this code yourself, the most common problem I see people encounter is their hash function in their language outputs hex digits rather than bytes. If you take the hex digits and then try to base 64 encode it, you're going to get some random thing that's not at all right. You have to make sure you find a shot hash function that outputs raw bytes and then base 64 encode the actual bytes. So in JavaScript, there's a way to do it, which is, I don't even remember the API, it's been so long since I wrote this. Oh, it looks like the default encoder does return the raw bytes in PHP. There's like a parameter you have to add on it. So just double check that the function you're using for calculating the hash outputs raw data, not hex encoded data. And then you base 64 URL encode that. So here are the two strings we're going to use for the exercise. Code verifier, it's just a random string. It has to be a certain length. So this generates something in the middle and then there is the hash of it. Now again, the point of the hash is that it's one way. So if you know this value, you can't figure out that one. But if you see this value, you can calculate this one. So the hash is what we're going to include in the URL because the URL is something that's being sent in the front channel in the browser where we don't know who's going to see it. So we can add code challenge and we also have to tell the server count code challenge method is S256. That's how we hashed it. Okay, so let's, these are getting small. This looks good. I think that's everything. Just for fun, let me make an intentional mistake like use the wrong redirect URL. I'll take that one out and let's see what happens when there's an error with this request. So okay, this one was bad enough that we didn't even get a single message. There is something wrong with this URL and Octor just says bad request. What's wrong with it? Actually, I see there's a problem. There's an extra space. This keeps happening to me when I copy these things. There's an extra space up there in the client ID. Okay, now we're getting a more helpful message. Now that we have an error, now that we have a valid client ID. So now we're getting a message saying the redirect URL is wrong, basically what that's saying. And that's because I have the wrong redirect URL in this request. So let me give her that space if I don't copy it again. And then if we include the actual correct redirect URL, then what's gonna happen is we will no longer get that error message. However, I wanna show you this in an incognito window first. So if I visit that URL and in an incognito window, I'm not logged in here so Octor's asking me to log in. If I visit it in this one, I am logged in so it's going to do something different. Okay, so for the exercise, where's my OAuth school tab? Okay, what we're gonna do is we're going to paste this URL in here because this is gonna do some debugging on it to tell you if you've done things wrong. For example, let me mess that up and run this. Yeah, it looks like you're missing some query string parameters. So double check that you've got everything in there and it looks like it's correct. This can't know if your code challenge is right yet because it doesn't know what your code verifier is. So again, if you've calculated the hash wrong, this might look okay and you'll fail the next step. Okay, so let me pause there. I see some questions. What about state? You don't really need it. State is a good question. A little bit of backstory on this. Before Pixie existed, the problem is that, let's see, let me click this login button. Okay, so what happened is this link actually takes me to Octa, right? You can see it is this URL and it opened up in a new tab and you didn't even see me at Octa because I was already logged in and I got redirected back immediately. This is this redirect step. Now here's the problem and here's what Pixie is solving, which state attempted to solve sort of. This link, anybody can visit this link, right? I've got a redirect URL on the internet. I'm not logged into this app yet because I'm trying to log into the app and there's a code up here which the app is gonna try to exchange for an access token and the problem is that this app, if I just type in junk, it doesn't know whether it's real or not, right? So it might try to go and exchange that for an access token at the OAuth server. Sending junk to its one thing, the more significant problem is if you can sort of like swap authorization codes between valid users in the middle of Flows, which is definitely possible. That's what state is trying to solve. Basically, what the state does is it means that I can no longer make arbitrary requests to this endpoint. So if we didn't have state here and we only had code, then anybody could just come in here and be like, oh, well, let's just try this one, see if that works. And it would go and make a post request over to Octa to exchange that. That's not great. So what we do is we have state and if I don't include, if I include an invalid state parameter, this app can then check to make sure that it was the state parameter that it generated before it goes and exchanges the code. So that was what state tried to do. That also has some problems. There are still some attacks you can pull off even with that mechanism in there. So then a few years later, Pixie came in, which actually solves all of that. So now with state and with Pixie, if you were to try to swap out somebody's authorization code, the next step would fail because of Pixie. That is way too much to get into to try to demonstrate that, but we do have a video on YouTube, on the Octa developer channel called authorization code injection. This one, I'll just drop this link in the chat as well. That is a demo of the exact, the exact step-by-step of how to pull off that attack and why Pixie solves it. So if you are curious about the details, feel free to watch that link. Okay, so state is sort of just like a first filter. Oh, and Yon says, doesn't state also help present CSRF and replay attacks? Yes, again, it helps and it's not necessarily a guarantee. Pixie does everything that state does, but better. So the state parameter, it's still a good idea to do it, because again, generally you want to add layers of security and not rely on just one piece. So it's like a good first pass at a filter to reject certain junk requests, but the Pixie is the one that's doing most of the work of protecting against code injection, code swapping, as well as CSRF. Okay, so Rachel says, you do need scope, let's see what happens if we don't include scope in the request. I'm gonna take it out of this URL, scope, we'll take that out and I get, so okay, it's happened so fast, it's so hard to tell. I went to Okta and I got sent back and instead of sending back a authorization code, I got sent back an error message in the query string and this webpage just helps spit out on the screen so it's easier to see, but it says invalid scope, the authorization server does not have any configured default scopes. So this is why we had to go create a scope and then include it in the request and you can see it's down here, it's in the middle of my list of parameters. I use the scope developer day, just because it doesn't mean anything right now, but it'll get us through this first step. Okay, if I click on that link, I get sent to Okta and I come back and now I have an authorization code. So what can we do with that? Yeah, first we're gonna verify that the state matches the one that we created in the beginning which it does, that looks like the same number, so we're good there and now we can go and exchange this authorization code. Could you have used any scope for now, any scope that you've defined in your OAuth server? Yeah, I don't care what scope you actually defined right now because we're not doing anything with scope yet. You just need something there. Okay, so where are we on the dock here? Since you're already logged into your Okta account, you'll be redirected back immediately. If you wanna see what happens for a new user, open in Cognito. You'll be redirected back here and sure enough we see that and if you've got the authorization code, you're ready to exchange it for the access token. So now we're gonna make a post request to the token endpoint. This is, you're welcome to do this however you want. You can use curl, you can use postman, you can use code in whatever language. All you need to do is be able to make a post request with some post body parameters. Personally, I find postman extremely cumbersome. It feels like it takes so much setup to make it work that I don't think it's worth it so I'm not going to be using that. I'm just going to use curl because it's already on the machine and there's not really anything to it. If you are, but yeah, it does not matter what you're using to make this post request. The point is that this is simulating code that would be in your app's server making that post request. If you are, if you're copying from this document, be careful because sometimes copying out of these things copies weird empty characters like how I somehow ended up copying an extra space character. It's probably safer to retype all of this and not copy and paste just because of the new lines issues and stuff. So I'm going to do this from scratch. So I'm going to type curl. We need to know the token request. So where is the token endpoint? Again, back to our metadata, copy that. So curl, token endpoint. I'm just going to do all one line. So we've got, we've got, let's just go through this list. Grant type, authorization code. That's how we know, that's how we tell the OAuth server that we're trying to exchange an authorization code. There are other grant types, for example, the client credentials grant type when there's no user involved or there's the device flow for like a smart TV, but we're doing the authorization code grant. We need to then tell the OAuth server which redirect URL we used. Redirect URI, which I've got up here. We've got, side note, redirect URI in this request was another similar protection against trying to avoid these tricky swap requests which is now redundant and Pixie again does that job better. So, but it's just required because of most implementations require it because it was more or less required in the spec even though it's not actually really doing anything anymore. Okay. So those two, next we have to include the app's credentials. Now there's multiple ways to include the credentials. You can put it in the post body or in an HTTP header. I'm gonna put it in the post body. So client ID, which I think I have it up in this document here. Let's make sure I don't copy a space. See, it copied a space. That's weird. Client secret. This is the app's password. Remember how I said it's the app's password? That means we do not want to use this if we are writing code in JavaScript or in a mobile app. Okay. That's, and if we include the code itself, we got from, where's my redirect tab? This one, here's the authorization code from the return. Now, this is not enough and I'll demonstrate what's wrong by actually making this request and we'll see what happens. We got back in the error from Octa saying pixie code verifier is required. This error is technically confusing. It's misleading because, but the point is that this first part is correct. Pixie code verifier is required. So, the, what that's because when we started this flow, the front channel request that the Octa got from the browser, not from the app contained this code challenge. So we have to prove that the same thing made this request. Remember that the, that Octa is seeing these two requests from different places. Octa sees this request from the browser and Octa sees this request from your app's server. So they're coming from two totally different places. How does Octa link them up and know that it's okay to return the access token to the thing using this authorization code? That's what the code challenge is for. So the code challenge is that hashed version. We need to send the code verifier from the server. So if we go back to, I had it here, code verifier. If I put this in the request, this should now no longer give us the error of pixie code verifier required. And sure enough, now we have a message that is the authorization code is invalid or has expired because it turns out these don't last forever. They're short lived, one-time use codes. So this authorization code we got has already expired because it's been several minutes since we've got it. So we have to go get a new one. So let's go back, let's close that tab. Let's go back here. We've got the same authorization request, right? Same code challenge, that's fine. And we're gonna go click log in. It's going to give us a new authorization code. And if we go and swap that out, we do this quick enough, it should work. And sure enough, we've got the access token. Now to complete this, we actually wanna take this whole token response and paste the whole thing, not just the access token, but paste the whole thing into here. And this tool will tell us if we've done everything right. And we did. It actually goes and checks to make sure that the access token is really valid and checks to make sure it's got the right scope and all that stuff. That's what that tool is doing. So if you had any problems or missed any steps, it would have told you. But again, that is why you only want to do this from a lot of orders you're using that you've created specifically for this. And don't put real access tokens into this, please. Okay, that is, that is done. Let me take a look at some of the other questions coming in. Yeah, so more questions about Pixie versus State. The, so there are a couple of uses of State that are possible still, that are useful. And one of the other reasons State is in there is so that your application has a way to persist data between steps without storing things in the app. Now, that's not necessarily a useful thing for you because in many cases you'll be writing code that uses server side sessions or encrypted cookie sessions in which case you already have a place to store things between the requests when the user leaves and comes back. Because remember the user is leaving your application and then coming back to your application later. And if you don't have a session or cookies or anything, then you wouldn't know that it's the same user coming back. So that is one thing you can use State for is to actually sort of use that as the way that you're persisting data between requests. If you're doing that, you have to make sure you are encrypting it or signing it in some format so that you can, you know that it's not been tampered with but that is a possibility. I feel like the vast majority of the time it's easy enough to just use the framework's own session mechanisms to maintain that data in which case you don't need the State to actually store that data. But in that case, the State is, I'd like to think of it as a first pass filter. So again, if you have a redirect URL, if you have your redirect URL here and if you were ignoring the State parameter, then what that means is that your application might try to do stuff with the authorization code even if it's being thrown junk. However, if you are doing Pixie, Pixie forces you to store that code verifier in your application logic somewhere, which means you've already got a place to know whether or not the browser that's returning is the same one that started. And then you're not, you don't have that problem. That's what I mean when I say Pixie kind of makes State irrelevant in most cases because you're gonna have to persist that code verifier somewhere. If you really wanted to get fancy, you could encrypt the code verifier and put that whole encrypted string in the State parameter. However, I don't see a lot of people doing that. I would go through several audits on whether that's actually safe to do before doing that in production, but it's at least theoretically possible to do it in a way that makes sense. But yeah, for the vast majority of the cases, if you're doing Pixie, you're gonna be storing that stuff on the server side session or even in JavaScript, in the JavaScript application context, wherever that is gonna be, then that already gives you what you need in order to know that you can't, you're not gonna be accepting unsolicited requests to your redirect endpoint. Okay, so how are we doing on getting the access token? You should at this point be able to, this is why I keep this in a text document. Take this authorization URL, visit it, go log in, get the authorization code, make the request with the authorization code and get an access token. Close that one, check the token and we're good. Cool, okay, we've got a little bit of time left. So let's do, oh, this is a great question. Do we really need to include the client secret when using Pixie? I'm glad you asked that question. The answer is yes. So Pixie and client secret have nothing to do with each other. They are completely different issues. They are both protecting things, but they're protecting different things. Now, so Pixie is protecting against CSRF attacks, which again are even a problem with the client secret. Pixie is also protecting against authorization code injection attacks, which again can also happen even if you have a client secret. And that video I linked above in the chat is a demonstration of that. The client secret is how the app authenticates itself to the token endpoint. That is only possible in the case that your application can protect the secret. If your application can't protect a secret, then it can't use it for authentication. Apps that can't protect a secret are gonna be JavaScript apps, mobile apps, desktop apps, any kind of, any time the code is running in an environment that the user controls. So just think about the client secret versus Pixie as completely separate issues. They're not connected. I know it's a little bit confusing because of the way that Pixie evolved and because of the way that some of this stuff has advice has changed over time. Pixie was originally created for the mobile app use case because of limitations in handling client secrets in mobile, but because of those same limitations, that also applies to JavaScript apps. But it turns out that there are other attacks that weren't considered when Pixie was created that Pixie actually solves. So again, client secret, Pixie are totally different issues and the answer is yes, you should always be doing Pixie and if you can use a secret, you should always use a secret. Okay, let's do one more topic here. I wanna introduce OpenID Connect and we're gonna see how easy it is to add it to the flow. And I think we can do that in the time we have left. So again, OpenID Connect is not a whole new thing. It's a small new thing. It is a layer on top of OAuth. So we've already seen how OAuth works. We've gone through a flow. We wanna see now, how do we actually learn about the user? Cause what we've done is we got an access token. That access token will let us go talk to an API to fetch data, but we don't know who the user is. The application gets, where's my access token? The application has this access token here. The only thing the app is gonna do with this access token is go use it in API requests. So OpenID Connect is how we can actually go and learn about what's the user's name, what's their email address. The way we're gonna do this is by introducing a new type of token called an ID token. This part is a little bit confusing because sometimes these look like access tokens because many systems use the same format for both. However, these are not the same kinds of tokens and you cannot mix them up or bad things will happen. So in general, tokens have an audience which is who the token is meant to be read by or understood by. So that's, you know, an audience is watching something, that's the audience of the token is who is supposed to be watching the token. The audience of a access token is an API. It's a resource server. That's the only party, the only role in this that is supposed to be actually looking at them and understanding what they mean. The audience of an ID token is the application. This means applications are never gonna look at access tokens and it means that applications are never going to send ID tokens to APIs. Okay, an ID token is a JSON web token. It's defined in the spec. A JSON web token is a three-part token containing a header payload and a signature. Inside the ID token are what are called a bunch of claims. These are things to talk about the user or about how they logged in or other things about the system. How do we get one? Well, we have to do a flow. How are we going to do a flow? In my opinion, the easiest way to do that is to use the flow that we've already done, the authorization code flow with Pixie. This has a couple of really super useful properties. If you ask for a ID token using the authorization code flow, you're gonna get it back at the same time as you get the access token. And what you're doing is you're getting it back over the back channel. And remember the properties I said about the back channel. You already know where it's from. You know that it's valid. You know it hasn't been tampered with. Basically what that means is that you can forget that it's a JSON web token and just read the claims out of the middle. So that's what we're gonna do. Let's go and give this one a shot. We're gonna skip over to exercise four on the website. So where is my, here it is. This one down here, I guess I'm not really numbered. So I'm gonna drop that link in the chat. What we're gonna do is we're gonna turn our previous work into an OpenID Connect request. And it turns out it's actually very easy. All we have to do is take this, which we know is an OAuth request. And we only have to add a new scope, OpenID. And then you put a plus because that's a space in URL characters. If we add the OpenID scope, let's see if this is gonna let us work. Oh, this is telling us to skip ahead a step. Let me just visit this URL without those scopes first. We got a new code. This looks the same, nothing's changed. We haven't written, we haven't changed any code as in adding the scope. If we exchange this, now look what we got back. It's kind of hard to read when it's all jumbled up. We've got access token, which ends here. And now we have an ID token. This is what contains the data about the user. Now, again, specifically because we got this from the token endpoint, I don't care that it's an ID token. I can just in fact take the middle part, which is the Base64 encoded JSON data and read that. So I'm just gonna copy only the middle part. I'm gonna go grab my Base64 decoder and decode that and take a look at what's inside. What's inside is this is the main one that we care about, sub, short for subject, that's who logged in. That's the ID of the user logged in. It's not necessarily a human readable or a meaningful name. It's meant to be the random string that random string that identifies this user. Nothing else in here is really talking about the user. Necessarily there's, this one is interesting. This one is how the user logged in, saying they logged in with a password. And then this one is when the user last typed a password at the OWL server. Because again, remember how I've logged into this OWL server already, now like an hour ago. So this is saying that this ID token was generated now, but the user last typed in their password a while ago. So if your app cares about that, it could use that information. The rest of this we don't care about because we got this over the back channel. Now, if you ever store an ID token in a cookie and send it back, like have your browser send it back to your app, or if you're passing an ID token from one app to, or if you're accepting an ID token from the outside world in any way, you do care that it's a JSON web token and you have to do signature validation. You have to do all the validation of these claims, which can get really tricky. And it can be very not obvious if you've missed a step because you can kind of just, it looks like it works even if you haven't done all the validation. That's why you hear a lot of people complain about JSON web tokens and why you hear that like JSON web tokens are bad. It's not that they're like inherently bad. It's just easy to sort of misuse them or forget to do things. And that's also the reason I like doing the authorization code flow with Pixie to get an ID token because then you don't need to worry about the JSON web token part of this. You just treat it as base 64 encoded JSON data and decode the middle part. Okay, so we've got the user ID. What about the user's name? So let's go back to our request. We have to add more scopes. So remember how there were a whole bunch of scopes to find by default on the authorization server? Let's go ahead and add profile and email to the request. If we do that, where is my request? So here's scope, open ID plus profile plus email. We'll leave the developer in there also, check the link. Now it lets us through, click log in. Again, this step doesn't change because it's just an authorization code and the app will exchange that for an ID token and then we have to copy the whole thing into this tool and check the work and now we have to make it happy by extracting the claims and actually confirming them. So let's go paste that here to extract the claims. But again, this is just base 64 decoding this data. You can do that however you want. So, oh, that's the wrong one. I wanna paste just the ID token. There we go. Here's the subject, what is the email address? Here it is and the name, copy that here. We'll go ahead and verify and we are done. So I kind of skipped through the instructions. Oh, I should probably share you that link. Here it is. So here is the actual lab text. That's the link to what we just did. So if you wanna step through it again in the remaining time, basically all we're doing is we're taking the first thing we did in the first exercise, adding in the scopes and then following the instructions on the OpenID exercise. Cool. So are there any other questions before we wrap up? What do you wanna do if you wanna access two different APIs, two different audiences or any two different access tokens? There's a bunch of different ways, a bunch of different options you have. So if you, first of all, your APIs could use the same audience. The audience is meant to represent which API is being accessed. Depending on whether those two different APIs are like part of the same system, you could separate out access to them by scopes instead of by audience. If they really are like two completely different systems like made by different departments or then you may wanna use different audiences for it. Octo does not let you add multiple audiences in a single OAuth server. It's basically one authorization server to one audience. So you would go to your authorization server list and add a new one and give it a new audience. I think Auth0 lets you do multiple audiences on the same authorization server. So different use cases there. So then in that case you could, oh, and yeah, we're getting some answers in the chat as well. The, again, depending on the OAuth server, so Octo and Auth0 handle this differently as well as other products handle it differently. Sometimes you can request a token with multiple audiences. Sometimes the server will let you only request a token or you don't even get it request the audience claim. It just will appear. But the other way to handle this is using scopes and we'll get more into that in the afternoon session at the end of the day. When I come back and we talk about APIs and we'll talk about designing scopes for those APIs which is where that comes into play more. Matthew asks, fat or thin ID tokens when do you get each and why? Another good question. So let's see. What we've looked at here is we've got some information in the ID token, right? These are the claims in the token. Now what this means is that the OAuth client asked for the, did in fact ask for the scope name and profile and email and then got back this information in the token. Some servers will not put it in the ID token and instead you would have to use the access token to request this information from an endpoint. This is basically the idea of, this is the fat versus thin token difference but anytime that you're like bundling this information up into a token, you've essentially created a cache. It is a cache. So this is a statement about this user record valid at this time which means if I go change my name on my account then this token hasn't changed, right? So if this gets, it's very specific into how you're using these things but if you are for example, putting this kind of information into access tokens or if you're putting it into ID tokens and then using ID tokens as your session identifier or putting it into a cookie and bringing it back to your app every time and reading it from there, you're reading a cache. So if you're ever looking at the ID token other than at the time it was created you're looking at potentially stale data. So if you want to know about the most up to date version of that information in the token that's when you would want to go to the thin token model or just ignore stuff in the token and look up the information at the OAuth server. There are trade offs to both because obviously it's never a good idea to just do one or the other but that's kind of the difference. Think of, just think of when you've got this JSON web token that is a cache of data that was created at the time the token was created. The system, the state and the system may have changed since then and you won't really know until you make a mistake by acting on stale data. So I feel like it's more of a concern with access tokens but that's for this afternoon's discussion. Great question. Okay, fantastic. So if you are watching this recap there should be links to all the resources down below as well. So hopefully you can find links to the exercises and the tools I used. Otherwise, thanks all for joining. This has been a lot of fun. And we will go ahead and wrap this up here and come back and in a half hour we'll come back and have the next session which will be the Auth0 session. So thanks a bunch. I will see you all shortly. See you back in a half hour and make sure you've got your Auth0 account set up if you're gonna join that session. Thanks.