What the Heck is OpenIDConnect?

Transcript

Details

Speaker 1:  I'd like to welcome Karl McGuinness from Okta to speak with you. Thank you. 

Karl McGuinness:  Welcome. Karl McGuinness, Senior Director, Identity, here at Okta. I look after a lot of our core technology and protocol stacks, and I'm excited to talk about OpenID Connect today. The legal people made me do that. Next one. Let's just define the word first, authentication, right? Authentication is verifying the identity of a user, a process, or a device, often as a prerequisite to giving access to something. We first have to verify the user to establish who the user is before we can give the user access. The most classic pattern for authentication is direct authentication. That's where you have your user identity store with a credential in it. The user goes, logs in, directly against that particularly database or identity store. The problem with direct authentication, though, is it's not scalable. Password re-use have to go create a new account, every single database or application I hit. Account proliferation is the result. The sign-on doesn't cross the boundary, so you end up getting a very poor user experience. 

It also propagates the idea that the application directly understands the credentials, which over time creates a different problem, which is you end up with credential technologies that end up being baked into these platforms that become very hard to kill. The big reason why the password is very hard to kill is you have, now, 20, 30 years of applications that are tightly coupled to that credential model. For example, as you can see here, on a phone or on a Windows PC, for example. 

There had to be something that was better than this direct authentication model, right? We thought hard about this in the early 2000s with prerequisites going to Kerberos, thinking about identity in these two separate roles. An identity provider that issues identity, and an application otherwise called a service provider, which trusts something that was issued by the identity provider as a way to establish who a user is. A great example of that technology here at this conference is that you guys all probably have heard of SAML, which is the gold standard for enterprise single sign-on. What SAML did was basically develop this idea of identity as attributes. I can define an info document of attributes, such as, here is an XML, is how SAML was built on. Or I can say, "Hey, I'm trying to issue identity about this particular user. I want to have some context data about how the user authenticated." I may have additional attributes like their name, their role, and I'm going to digitally sign this with a PKI certificate from the identity provider that gives the service provider the ability to validate that and use those attributes as a way to sign in. Now we've decoupled those two particular roles.

SAML was key technology in the era of the mid-2000s, but what's changed since 2005? Well, first, we're seeing new use cases. We're no longer in a browser centric world where we're just able to rely on cookies and browsers. We have all sorts of application types that we now need to think about authentication. These applications are not just on a single platform. We're trying to deliver the best user experiences across multiple platforms. Our web stacks have changed. We used to have these thicker, SOA web service, SOAP-based web services, and we've now adopted the GET POST PUT, the simple, restful web services, which has led to what we now conventionally call the API economy, where our applications are being composed for multiple different APIs.

If all our systems now are built on these APIs and we have this problem of how do I give access to an API to access my data without giving it my credential? If I give it my password, it can act as me and go out and do things as me. I don't want to just give a random internet application the ability to be me, because I don't know what it's going to do. We invented a scenario around that that you've probably used on the web today. If you've ever seen one of these dialogues on the internet, you've seen the solution, which is called OAuth 2. OAuth 2 is a delegation protocol, which addresses this core use case. What I can do is an app can request an ability to act on your behalf. The user now has a role where he can say, "Yes, I want to grant that application the ability to access." What am I going to grant it? Well, I get to pick on that consent, and then the application gets a token that can then act in that delegation model. That's the simplistic model of OAuth 2.

You can use an analogy to try to connect it. You can think of, we're at a hotel. You probably walked through, when you checked in, you went through some central agent. You authenticated to that agent. You got back a token, and you can use that token to go access your hotel room. At the summary level, you could think of OAuth in that model.

The actual terminology, because we're going to be talking a lot about these terms, is ... The OAuth client is the application that's acting on your behalf. You are the resource owner that's granting access. The authorization server is the server that's going to issue access in the form of a token, and then the resource server is the API that I'm presenting the token to. 

Which brings us to our next term, authorization. Authorization, a decision to grant access, typically automated by evaluating a subject's attributes. If authentication gives us those rich attributes, we can inspect those attributes to make authorization decisions. Authorization needs authentication but is different than authentication. In OAuth 2, this is modeled as scopes. If you've seen these dialogues, what it's saying is the application is trying to give you access to these permissions and not these other permissions. A scope is just a bundle of permissions defined by the application that gives the user the ability to give consent. Some examples of that may be, "Hey, I'm trying to get access to my friends in the application," maybe to my photos, or if I'm in an enterprise application, maybe the scope is the ability to manage customers. 

The key thing here is that the scopes decouple two key aspects: making the decision about the authorization policy about what a user can do versus the enforcement of when I'm actually using the token. We'll come back to that in a second. The key thing to remember here about scopes is it requires consent. It requires sensitivity of the user. It has to be pre-approved if it's in more of a trusted model. The key role that's making this happen is the authorization server. The authorization server is where we can put our authorization logic. The authorization is the policy decision in the authorization part of the statement. I can say, "Is this user still a valid user in my system? Is this application an application I know about? What is the user authorized to be able to do? What are the attributes about this user I want to be able to issue to, and even down to lifetime?" That's just some examples of the types of things that an authorization is making a policy decision about.

Once the decision's been made and a token's been minted, the token can be presented to the resource server, and that's where enforcement happens. I present the token to the API, and that's where now enforcement happens. The resource server is being able to make the decision of, "Hey, for this access, does the token have the right scope?" The resource server can do it locally. It doesn't necessarily have to go back to the authorization server to do that. It can leverage sign-in tokens as a mechanism to do that. 

That brings us to the existential question: Is OAuth 2 an authentication protocol? The problem here is, here be dragons. The problem is, is that if you think of OAuth 2 as many of these social providers have implemented it, it makes a key assumption. It's making an assumption that I'm holding the key, therefore, I am the owner of the resource, and that may not necessarily be true. This is a hard distinction to really get to, but this gets to why OpenID Connect exists, because OAuth 2, as I mentioned before, was a delegation protocol. I'm just giving the application access to a resource. Separating authentication from authorization is the key confusion part, and it even gets more confusing, because OpenID Connect is built on OAuth 2.0, so let's unpack that for the rest of the presentation, and hopefully by the end of this, we have a pretty clear understanding on why OpenID Connect is different or solves a different use case for authentication. 

How will this work? You can imagine that you have an API resource, /me, my profile data. The API I'm trying to get access to is a me resource, and I'm going to go to an OAuth server and get access to /me. That is fundamentally how a social provider would look at it. I have my own social profile. I do an OAuth flow, get access to the /me resource. The problem here is that token that that application just got back the authorization server, it's opaque to that client. The client doesn't know what's in the token. It can't read what's in the token, because the token was meant for the API. It wasn't meant for the application. This opens up a lot of vulnerabilities here, because this is a web-based protocol that does redirects. This gives an opportunity for an attacker potentially to swap tokens out, do things at the http layer, because the application itself can't actually say who this user is. All it can do is go to the /me endpoint and say, "Here's a token that lets me have access to the /me resource." That's the distinction there. The /me resource is the delegated access. The user authenticated. The application doesn't know because it has no context about that.

What do I actually want to know, though? Well, I want to know who the user is. I want to know did the user intend to log in to /me. I want to when did the actual user authenticate, and potentially, how did they actually authenticate? Was it with a password or something else? There's really no way to answer these questions in a pure OAuth 2 flow. 

Which brings us to OpenID Connect. OpenID Connect is a protocol that's built on OAuth 2, trying to address that key gap. It adds two distinctive aspects on top of OAuth 2. First, it adds a token that's designed for the application to understand the user's identity. We're going to call that the identity token. Then, because every application has to have a /me endpoint, instead of letting every application define its own way, let's just standardize what that looks like. We call that a UserInfo endpoint. That's a standardization of that /me resource, and that's important because we'll come back to that in a minute about fetching more additional data. 

We're standardizing a bunch of aspects about OAuth here, because I want to know how to request access to a user's profile. How do I describe that access? How do I say, "I want access to the user's phone number, their address, or their profile"? We do that by standardizing a set of scopes about a user's info. To make this more scalable, let's learn from some of the lessons in the past of identity protocols like SAML, and let's define a much more dynamic way to achieve the integration between the application and the identity provider. We don't want to just base this on social auth use cases. We want to take the lessons learned from SAML for high assurance scenarios, enterprise scenarios, and be able to use that as well on top of OpenID Connect.

OpenID Connect is a modern identity protocol built on top of OAuth 2, and it's implemented by the world's largest identity providers, Google, Microsoft, and Okta. You can take away in your mental model, you can take OAuth 2, the best parts of SAML, the easiness of Facebook Connect. That's the mental picture here. I want all of the goodness of OAuth 2. I want some of that enterprise SAML goodness. And I want to make it easy for developers.

Let's look at a high-level flow of how OpenID Connect would work. We have our client application, and on the right we have our authorization server. The client, first, is going to discover the metadata about OpenID Connect. OpenID Connect publishes a well-known resource about metadata that it discovers, "Hey, here are the additional endpoints. Here are things that you can ask that I make available." Then I do an OAuth flow and I request an identity token from the authorization server. I then can then use that metadata to go fetch the sign-in keys that were used to sign the identity token dynamically, and then validate that identity token locally. Now, the application, without having to make a call to a REST API, is able to get the identity of the user in a token, be able to fetch the metadata about how that token was signed, and validate the signature all locally. If I want to get additional data, I can use that access token to go back to the authorization server and fetch more additional data if I want to. That's fundamentally the high-level view of what OpenID Connect provides.

Let's dig into a few of those pieces we introduced. The first was that metadata. This is a pretty awesome aspect about OpenID Connect, is that you can just take the name of your OpenID Connect server, add ./well-known/openid-connectconfiguration, do a GET call on that, and get back a JSON document that describes everything you need to know about OpenID Connect. It can talk about, "Here are all your endpoints. Here are the different OAuth flows I support. Here are the different scopes you can request." And even, "Here are the attributes that I support that can come back into the tokens." That provides a quick, easy developer. One URL is all I need to do to configure my application. 

The identity token. In order to make this possible, we have to standardize on this identity token format. OpenID Connect takes a dependency on another format called JSON Web Token. We move from a world of angle brackets with XML to a world of JSON. You can think of this now as, how do we represent security tokens in JSON that have all of the same type of security properties? I want to make sure that they can be signed, they can be encrypted. A JSON Web Token is a format to represent a token. On the right, you can see I have a bunch of additional claims about the user. It's very similar to that SAML assertion I showed you at the beginning of the slides, but in a much more compact, JSON form.

It takes a set of standards to make this possible. OpenID Connect relies on a set of foundational technologies called JavaScript Object Signing and Encryption. That gives us the rich, primitive properties to be able to handle the signatures and the encryption. What's awesome about this even, is that this even now is baked into modern browsers. I don't even have to think about going out and having to go understand XML digital signatures with these really complex libraries. You have the base crypto-operations as part of the browser standards. We're very much aligned with a lot of the same technologies that we're already using, which is pretty awesome.

Just a quick comparison just to see from both sides how it lands is, we would say that OpenID Connect is more user centric versus organization centric. Where SAML required this federation to happen between two companies, here we have a more user first protocol design based on more modern developer-friendly protocols like JSON and REST, using more modern security token formats, like JavaScript tokens or JSON Web Tokens, and the discovery aspects can be static or dynamic. We're improving on some of the static-ness of SAML and making things much more dynamic and giving the developer a flexibility on, do I want to get all of the data in the token and have this really fat token? Or do I really want to potentially have a smaller token and be able to call REST APIs in the background? I can mix my use cases, which makes it a much more flexible protocol.

The key thing that, really, I think, makes this all really possible is really thinking about when you have a protocol, how do I make sure a client and a server are actually compatible? This has always been a problem with any protocol that's been there is that different vendors may do things slightly different. One of the ways that you can address that problem is really thinking about, how do I make it easy for people to certify that their application does the right things? The Open ID Foundation has created an automated test suite for both client developers and providers to test interoperability. This helps scales the ecosystem of both providers and clients and making sure that all the security things that you need to do right are implemented right, all the optional things are optional, but the required things are required. We have a unique opportunity here, unlike previous technologies, to really have an ecosystem approach here, because there's a rich set of certifications available with OpenID Connect.

Why should I be using OpenID Connect in the first place? Well, one is OAuth 2 and OpenID Connect complement each other. I may already be using OAuth 2 for distinct use cases. I may have a browser application that wants to talk to a web application. I might use OpenID Connect to authenticate that user to the web app, but that web app, because we're in the API economy, may be making a bunch of background API calls. I'd use OAuth 2 for that, because I'm just needing access to a resource. The browser could immediately just call an API, but now we've got this native app as well, and this native app also wants to access some of the richness of this API. It might use OpenID Connect to authentication and OAuth 2 to get access to the custom objects, say it's a patient or say it's a customer record. The server resource may also want to use OAuth 2 to get it, which may, and again, use OAuth 2 to hit another API. What you're seeing here is OpenID Connect provides the user authentication layer on top of something that you may already be wanting to do with OAuth 2, and they work really nice together. 

I mentioned that certification really made things compatible from both the client side and the server side, and I think one of the key aspects here is learning from the past and making it easy for the developer to write the application and making it a little bit harder for the guy implementing the OpenID Connect provider, because that will allow the ecosystem of applications to leverage OpenID Connect. If it's equal amount of work for the provider and the consumer, then it becomes a lot more friction for each application you want to onboard, so we'd rather push a little more complexity to the provider and make the client super easy to develop. If you have an OAuth 2 client, enabling it to speak OpenID Connect is just adding intelligence about a couple key aspects. One is, can I understand this metadata to understand the configuration? And can I understand how to validate an identity token? If I can do those two things, I can probably add support to my application today for OpenID Connect.

What this allows you to think about from an app dev perspective is moving identity outside of your application, moving authentication outside of your application, to a shared service. You can imagine something like, say, M life, which is the rewards program for our and many hotels, where each brand may have its own separate website. It may have its own separate enrollment processes. It may have its own separate user stores, but I want to create, in this new, modern world, one identity service that can service every one of these brands. And each application, whether it's written on a mobile device, whether it's written on a web application, can just use a shared, central identity service. OpenID Connect provides that architectural level in your applications so that each application doesn't need to be an expert and understand everything about identity enrollment, and authentication can just be a client and consume identity. 

Let's get started. Let's see how we could use OpenID Connect. The first thing I have to do is I have to register my application with the OAuth server, the authorization service, the OpenID Connect provider, so that my application knows who it is. I then have to pick a couple different aspects and add this to a URL. First, I have to pick, how do I want my OAuth responses returned? We'll come back and talk a little more detail about the fine-grainedness of the OAuth flows. I have to pick, what are my scopes? The required one is OpenID, but I may want additional profile information, for example. Then, depending on whether I'm on a browser or I'm on a native application, I may want to pick how I want the data returned to me. Do I want it in a query parameter? Do I want it in a fragment? OpenID Connect is just basically saying, "What do I want? How do I want it back?" And then the third part is, "How do I want the authentication experience displayed?" You can provide a hint. You can say, "I want the user to have to enter in their credentials. I'm okay with them using an existing session with a session cookie." Maybe I want to give it a hint saying I'm on a touchscreen or maybe a hint that I'm on a pop-up type experience. 

The client basically just has to say, "How do I want my OAuth responses? How do I want the user experience displayed? What data am I trying to get access to?" And then the third part is really just implementing the security best practices. Because we're a web-based protocol, we have to do a few things. We've got to make sure we have some of the best practices, such as making sure we protect our app from CSRF. We've got to make sure we have a nonce to make sure tokens can't be replayed. And we have to make sure that the URL that we're redirecting back has been whitelisted. There's a couple of security best practices we have to do to make this work, but if you combine this into a single URL and make a request, you can do OpenID Connect.

On the left, here, we have a traditional OAuth 2 request. This a request that your application may be making today. Here I'm trying to get access to an API read scope. I'm going to make a request to the OAuth server using a code flow. Then a user is going to authenticate, authorize, and the application's going to get a code redirected back. What would we do to this to make it OpenID Connect-enabled? Well, we're just going to add the OpenID scope, and we're going to add a nonce. Now we're making an OpenID Connect request. Similar on the next part of the ability, now I need to get my tokens. I've already been authorized. I've gotten that delegation permission from the end user. Now my applications wants to get tokens. Here I'm exchanging that code for my tokens on the left side. On the right side, nothing changes on the request object, but now on the response object, I get back that identity token that describes the user. As you can see, it layers nice and neatly right on top of OAuth 2 just by defining some of these additional parameters to make the OpenID Connect request happen. 

I have different application types. I mentioned OAuth 2 can meet different use cases depending on which application you are. We call those OAuth flows. That has a lot to do with the client capabilities. On a native application that has different properties than, say, a single-page web app that doesn't want a redirect, potentially, versus a web server that can protect secrets and store a secret on the back end that it can use to authorize the data. The service call doesn't typically have a user context, so the app is really just acting as itself. I have to pick the right flow for the right use case. 

Let's go over the SPA use case. We call that the implicit flow. I have my four OAuth roles here. I have my API, which is the UserInfo endpoint. I have my authorization server, which speaks both OAuth 2 and OpenID Connect, my end user, and my app, my SPA. The user fires up the SPA app, goes to the URL. The SPA app basically issues an http redirect with those parameters, the client ID, the scope, the redirect URL, how it wants it displayed. The user then gets prompted for authentication as you would expect. The user authenticates and authorizes, and then what ends up happening is I get issued an identity token, and if I ask for it, an access token redirected back to my application. The SPA application now has the ability to authenticate the user with the identity token and use the access token that it just got back to get more data from the UserInfo endpoint.

Now we're switching to new application type. This is your traditional web server. This is your Java server. This is your .net server, your Python server. It may have a traditional web server that wants to authenticate a user. You would use the authorization code flow. This flow, it starts very similar. The user navigates to the application. The application issues a redirect to the authorization server, making sure I'm saying I want to use OpenID Connect. The user's going to authenticate. It's going to get back in the response something a little bit different than the previous one. I'm not just going to get that access token. Depending on how I made my request, I might get the identity of the user back here and an identity token, as well as that authorization code, which is that proof that the user has authorized me so that my application can go back and get tokens securely on the other channel.

What we do now is we take that authorization grant, that consent, that proof that the user has authorized me, go back to the authorization server and exchange that for more tokens. So this is a much more secure flow, because now the client can authenticate to the authorization server so that if anyone grabbed that authorization code, they couldn't just directly consume it and get access to the tokens. We use this on the web server because it can make sure it can securely authenticate. Just like in the first flow, if I want to get more data, I can go ahead and do that.

In both of these scenarios, we typically deal with sessions. We're logging into a web app or we're logging into a single-page app, and we usually want to get a session. We want to control some session aspects about it. What we say is, you should think about the identity token as a way to authenticate the user, but you should create a session in your application with that data that you got back from the identity token. The identity token will have some identifier about the user, the subject. You'll use that to say, "That's the same user as the last time he's logged in." You might link that to your database of your additional existing user. You may create a user on demand. But your application's going to typically take over and issue its own session with a session cookie to protect the user as he interacts with that application, because the authentication step has been done.

You want to try to avoid treating the identity token as your session cookie. It's very tempting in a single-page app, because I don't want to have to think about deployment complexity, really, if I have a low balance web server, state management. It'd be just nice if it was all taken care of for me. There's definitely a very tempting way to look at it. The thing to take away is the identity token really doesn't really talk about your application's session. The identity token is really about the identity about the user that authenticated at the authorization server. The identity token may have PI data or additional data about it that you may not want being passed back and forth with every request. There's some things to be concerned about. The recommendation here is really to try to think about OpenID Connect in a typical web server or single-page app as a way to log into your app, but your app should really think about managing its own sessions. 

Let's talk about a native app now. We went SPA. We've now talked about a traditional web app. This is your iOS/Android app. This is what we saw in the keynote today. The native application, the user basically launches the app on the home screen. The application then uses the system browser, so it uses the pop, slides in. You'll see the system browser take over. This is a key aspect here. This makes sure that the application itself can't read the user's credentials and the user's in full control of this part of the flow. He can then interact with the authorization server and give the application access. He can authenticate just like we saw with the web authentication flow, and he's going to come back with that authorization code that he's able to exchange it for. At this time the browser closes away, and you're back into the native application. It uses something called PKCE, which we talked about is a way to secure the fact that on a mobile phone, there's the ability to accept these authorization codes, because one app could potentially intercept another app's authorization code. Once I've gotten the authorization code, I can go back and get my tokens to give me access about the user's identity. 

What you see is a slight variation over a web server, so a native app and a web server work almost the same, except for the fact that the native app doesn't really have a way to authentication to the authorization server, because it's an app downloaded from the app store, whereas your web servers that you traditionally deploy on your infrastructure can be deployed with a secret when you deploy those web servers, because it's really within your sphere of things that you can control. This is code that's running on the mobile device that was downloaded from the app store, so we have a slight variation of that flow to make this possible.

Which brings us to the native app's best practices. I mentioned you don't really want to be using an embedded web view for these kind of flows, which is very tempting, because I get to more tightly control that user experience. The reason why I don't necessarily want to be doing that is the application that's running can directly get access to the user's credential as they type them in. That embedded web view is not just a trusted browser running on the operating system. It's part of your application's code. I can inject JavaScript into it, third-party JavaScript that's already running. I'm sure I'm using some third party marketing tracking data that's onto my application. That JavaScript can potentially get access to the user's credentials, which defeats the point of what we're trying to achieve. 

What we want to be able to do is make sure that the user is in full control of the authentication, the application can't get access to the user's credentials, so it can't impersonate the end user. From a user experience perspective, the user always has to re-authenticate every time they log in, which is a pain point if I happen to have a social identity provider. Maybe I want to log into an application with Facebook. Maybe I want to log in with Google. If I have to do this embedded flow every time, it doesn't know that I've already been signed into Google, because it's a sandbox browser. It doesn't have session cookies, so I have to re-authenticate every time I log back into the application, which creates a poor user experience. 

Then, finally, back to that beginning, which is new authentications are evolving. We may want to start thinking about passwordless authentication. Maybe we want to start thinking about strong authentication with multi-factor authentication. This gives the user the ability to authenticate with the identity provider without going back and having to change the application code, which is pretty nice. I mentioned before, what you don't want to be doing is don't ship apps in the App Store with secrets. They're not secrets. Anything in the App Store can be decompiled. You can get data out of it. Don't think that the secrets that you're putting into the App Store are truly secret. You should treat the native application just like a public app on the internet. 

You should use this advanced standard called PKCE, which is proof keys, to secure this exchange. You don't want a malicious app on the phone to potentially grab the redirect, so this is an advanced scenario, which brings me to the last point, which is there's been a lot of work in the OAuth community to think about these mobile scenarios and the best practices around mobile. You don't want to roll your own. You want to follow the best practices that have been developed over the last year or two by the OAuth community on how to go about doing this right. In fact, even better than doing that, you should just probably use something called AppAuth. The OpenID Foundation sponsored the development of a toolkit for iOS, macOS, Android, and thick client JavaScript applications like Electron and such, to be able to do all these OAuth flows with the best practices without you having to think anything about it. Okta, what we demoed today in the keynote was just basically a thin wrapper over this. Our guidance to everybody is get out of the business of your application to understanding how to use the credentials. Just use OAuth. It has thought about all the hard parts for you, and you just have to just add a few lines of code to your application and you can leverage the OpenID Connect in OAuth.

You can go to developer.okta.com and sign up for a developer account now and get access to an OpenID Connect-certified implementation, an OAuth 2 server with samples with AppAuth best practices built into it, if you're interested in going down and getting going with it. What we saw also in the keynote was really taking some of these choices about which flow should I use, what scenario should I be using, and trying to make it easy for the developer to get going with the right best practices. If I pick my native application, it's already going to say, use the code flow. It's already going to fill in some of the right data that we're expecting the flow patterns to use. The same would go for a single-page application or a server-side traditional web application. The developer experience in Okta is really trying to put you on the right path to make the best choices without you having to do too much extra work.

We also have an additional piece of technology here that is for more advanced use cases. We have an embeddable widget that is built on top of Okta's APIs to really, for single-page app experiences where your app is trusted with the Okta deployment, you're treating Okta as your identity layer for your particular product. The ability to embed that directly inside of your application, and it's built on top of an OAuth and OpenID Connect client that handles a lot of this JavaScript-level integrations for you. You can think of AppAuth pattern as what you want to do for addressing native apps. This is the tool set that you want to be thinking about if you're building on top of Okta, and Okta's really powering your entire application stack, for how you might want to do it for a single-paged application.

Coming back to that key discussion topic, so we've talked a bit about what OpenID Connect can do for you, a little bit about how you can take a traditional OAuth flow and make it OpenID Connect-enabled, a little bit about the different flows and best practices you might want to use, but I want to circle back to that important question, which is how does OpenID Connect enable secure authentication, and secure being the right property here? It starts with a little bit of just thinking about token issuer and token audiences. You can think of a token as having an audience just like a check has an audience. You don't want to give out a blank check, because anybody can cash the check. You want to make sure that that check has a particular user that that token was intended for. We call that the token audience. 

It's very important to think about tokens as who issued the token, the issuer, and who the audience of the token is, because different use cases may have different issuers and different audiences. You don't want to replay a token that was issued by A and played at B if that wasn't trusted. Let's see what that looks like. Token issuer and token audience, here. I have my authorization server, which is my OpenID Connect and OAuth 2 authorization server. I have my client, and I have two different APIs here. I have api.example.com and an.example.org, so two different APIs, but they both trust the same authorization server. And the client as well trusts the authorization server. I do my OpenID Connect flow, and I get back an identity token and an access token. The identity token describes the data about the user. The key part here is the audience of the identity token is the client. It's the client identifier. If I take that token and try to use it at api.example.com or use it at an.example.org, it has a different audience. If those applications are well-written, they will reject that request, because it should be expecting itself as an audience and it's not the right audience, even though I trust the authorization server. I trust, potentially, the same signature keys and certificates that may be issued, but I'm a different audience and I shouldn't accept that.

Conversely, you could look at the access token similarly. The access token is, in this example here, is issued to api.example.com. Now, I can't read that token in the client. I shouldn't be able to read that token in the client, and I shouldn't be able to use that token on another API that that wasn't used for. In that example, I could only use it on api.example.com. This identity token's becoming critical for not just a different audience, but it's becoming critical because it's binding a lot of these different aspects of OAuth together. When I make an OAuth request, it's just a redirect. The redirect, typically, is not signed data. There's different parameters in there that can be messed with. An attacker can mess with those particular parameters. What comes back, I want to make sure, is paired to that request that I made. I want to make sure that the response data wasn't mess with as well. 

What the identity token can do, is it can contain a hash of the authorization code or of the access token, signed, so that I can make sure that the tokens that are coming back were tied to my request. Again, we have that nonce property. That nonce is that number used once that I generated for my authentication session. I gave it to the authorization server. I have proof that it came back to me. Yup, it's the same nonce, so I know it's for this authentication request, and now when I validate the signature of the identity token, yup, it came from the authorization server. It has the right audience. I can look, now, at the tokens that came back and say, "Well, are those the tokens that also came back?" I can check the hashes and say, "Yes, they've come back to me." That prevents a lot of the attack surface area of an attacker coming in, potentially, and swapping out a token or swapping out an authorization code. Again, rolling your own authentication protocol in OAuth 2, these are the types of challenges that you have to think about. You're in the advanced world of trying to design a security protocol, and that's definitely not what you want to be doing.

The last aspect about it that's key about OpenID Connect is assurance. We say assurance is, "How sure am I that you are who you say you are?" The thing about assurance is that it decreases over time. Everybody has, when you unlock your keyboard, a high degree of assurance because you just entered your password, that's you sitting at your desktop. But if I go get a cup of coffee, maybe I don't lock my laptop, I have less assurance that it's still you behind that keyboard. It could be some other user sitting at that keyboard, so my assurance has decreased.

In an authentication protocol, I want to get some of this metadata about the authentication event, because I want to make a decision about the assurance of the user. Maybe I want to require a fresh authentication. One way I need to do that, is I need a timestamp of when the user authenticated, so I can know the actual instant they entered their credentials. And then I may want to say, "That's not good enough for me." I want to go back to the authorization server and say, "Give me an identity token where the time they last logged in has a max age of some value, say one hour, one day, one month." You can have a long-lived session in your application and they do an OAuth flow or an OpenID Connect flow, they come back and they say, "Well, actually, the user authenticated a month ago." You're like, "Well, that's not good enough for me. I want to make sure it's still the same user." I can go back and tell them to force them to log back in again. That's a really awesome property of OpenID Connect.

The other is understanding a little bit about how the user authenticated. All authentication across all identity providers are not the same. Okta serves both customer identity, partner identity, contractor identity. You may have different use cases that want different authentication types, and your application may want to know about that. One thing that the authentication provider can do is to stamp into the identity token how the user authenticated. In this example here, I'm stamping in that the user authenticated with a password. They also did MFA, but they didn't just to MFA with an SMS. They did MFA with a cryptographic key that the user had to put their fingerprint on and presence test that they were on the device. I've got all that metadata right here about how the user authenticated. There's a whole standardized definitions of all the different authentication factors, or authentication methods, to describe how a user authenticated, from biometrics to types of tokens to SMS, that the identity provider can give the application metadata about to make that assurance test.

Finally, that may not be good enough. Maybe I want to define my own application-level concerns here. Maybe I'm doing some sort of transaction model where I want to make sure to approve this transaction, the user has a particular authentication properties that meet my application requirements. I can define an application-level context class that both the application and the OpenID Connect provider agree upon and a policy that was enforced. A common example, a more modern example about that, is I want to maybe make sure that the user authenticated with something that was phishing-resistant. The application can say, "When I redirect you to the identity provider, I want to make sure that the user authenticated with a phishing-resistant authenticator." That'd be something where it wasn't easy to just be able to take a shared secret or a password and use that to authenticate. It gives the app the ability to request some policy about how the user should authenticate, which then can be verified on the response back that, yes, he did do what I asked him to do. This gives a way to communicate the requirements between the app and the identity provider.

All of these properties here really add that rich security layer on top of OpenID Connect. We added the ability to have a token that was issued for me. We added the ability to have a sign-in token to validate that it was, indeed, from the identity provider. We made sure that any tokens that were returned in the responses couldn't have been fake, because we have the hashes of them. We also were able to understand a bit about the context about how the user authenticated to make decisions about them. That's what makes OpenID Connect a very powerful identity layer for your applications.

For the last few minutes here, let's talk a little bit about where OpenID Connect is going. OpenID Connect comes from the OpenID Foundation, so it's a foundation of open standards addressing a wide range of use cases. OpenID Connect is the core authentication layer at the bottom, but as we move forward to different use cases, we may need to define new profiles or extensions that address domain-specific problems or additional net new use cases. These go into working groups that work across the industry to figure out, how should we best leverage OpenID Connect as that base plumbing, and add the pieces we need to address new use cases, such as, is this a government use case or is this a financial use case? Those might be examples of things you need to do.

One I want to call up that's sort of interesting that we're looking at, just to call up where things are going, is the ability to think about the user registration process and simplifying that with OpenID Connect. The ability to know, "Hey, I've logged into a bunch of different websites with the same identity provider. When I go to a new application, I just want to pick the one that I already typically use. I don't want to have to have the sign-up friction of entering my name, entering my password. I may not want to use a social auth provider. Maybe I just want to keep using my name and password. How do I simplify that experience of registering and signing up and integrating with that sign-up process on top of OpenID Connect?" That's called the account chooser Open YOLO working group, which is interesting, to help address that problem. What's great about that is it's got a lot of backing from Google and the operating system guys that tool that from the OS layer.

Finally, the last one I want to give a hint to is we're not done yet from the security perspective. We still have some properties of security we really want to get to. The main thing is man in the middle. We're still tied to this TLS. Everything that we've been talking about today really takes a dependency that all the exchanges happen over SSL/TLS, and we all know that that's a vulnerable channel. What we want to be able to do is move to a model where the tokens and the cookies that get exchanged between these flows can't be intercepted and replayed outside of the machine. We want to bind them to the machine, is really what we want to be able to get to. We call that channel binding, and that's an additional set of work from both the http layer, from the web server, from the web browsers, from the TLS, baking it deep into the stack and all the way up to OpenID Connect, to be able to take these tokens that we've been talking about today and making sure that they can't be replayed, which gives us that really strong assurance that it's still the same user tomorrow when I reuse that access token. That's the last piece I wanted to mention there on where things are going.

Summarizing OpenID Connect. OpenID Connect, a modern authentication protocol built on OAuth 2. It can support all your application use types, single-page app, web server, native application. We can get additional user attributes. Everything doesn't have to be in the tokens. My app has the ability, if it wants to, to make decisions about how the user authenticated. I'm not just getting the fact of, "Here's the user's name." I have data about the authentication context. I use OpenID Connect to authenticate a user. Remember, ID tokens are for your app. They're the audience, and I use OAuth 2 to get access to an API, to a protected resource. The access tokens are for your APIs. Don't roll your own authentication protocol on OAuth 2. OpenID Connect is the base layer going forward, and you'll see it being used in new use cases going forward as the base internet identity authentication layer. 

Thank you guys for coming out, and I think I have two minutes if anybody has a question in two minutes. 

Karl McGuinness:  Yeah. Yeah, so this really gets into a couple of questions. One is, make sure your identity provider supports OpenID Connect. There's still identity providers out there that don't support OpenID Connect, so that might be one reason. But in general, the guidance is, for net new application development, you should use OpenID Connect. SAML's a great fully-baked protocol. It's not really heavily evolving to all these new scenarios. If all I need is generic web SSO with the widest possible compatibility from every single identity provider on the planet, SAML might be the right technology. But if I'm really thinking about net new experiences, getting myself set up for mobile, different client access types, I probably want to, if I'm starting from scratch, you probably want to use OpenID Connect going forward.

Cool. Thank you guys very much. Oh, one more?

Audience:  There are new app models coming through. So for example, with a PWA, do I think about that as a SPA or a native app?

Karl McGuinness:  PWA?

Audience:​  Progressive web apps.

Karl McGuinness:  Progressive web apps? That gets interesting. Sorry, the question was, PWAs, the offline web apps, standards. The ability to have a mobile app kind of act like a native app offline. It's interesting because there's also other technologies that are related to that called service workers, so it's interesting to think about service workers as this other, additional channel. But the key thing to take away is just like a native application, it can't have a protected secret, because it's distributed over the web and you can extract the secret. That's usually the biggest question, is can it hold a secret, protect a secret? If it is, then you can use the traditional code flow-type technologies. If it can't protect a secret, you probably want to, at best, use the native-like flow with a PKCE to protect it or fall back to implicit if you can't do that.

Cool. Thank you, guys.

Forget about the frustration of SAML and your worries about how to secure your API and single page applications. In this talk, you’ll learn how OpenID Connect will help you secure your APIs as well as your web, mobile, single-page, and desktop applications.