Skip to content

OpenID Connect

Adarsh Kumar Maurya edited this page Dec 10, 2018 · 3 revisions

Overview

So, now we want to talk about OpenID Connect. So, OpenID Connect is really a specification that fits on top of OAuth2. Meaning it reuses its message format, like the query string format, like how token responses look like. But to implement authentication. Now you might wonder, why do I need a separate specification for that? And I first want to introduce you to why OAuth2 on its own is not enough for authentication. Then I want to show you what OpenID Connect adds to OAuth2 to make authentication secure. And then again, I want to show you or walk you through a typical OpenID Connect Flow, how to do authentication.

OAuth2 and Authentication

When you're reading the spec they make it very, very clear that OAuth is for authorization, or especially, they call it delegated authorization. And by now, we know what that means, We want to give an application access to a third party resource on your behalf. So, we are delegating an access token. So, we are delegating access and authorization decision AKA the content view is involved so that the access token can hold information for the resource server can do access control what this application can do your behalf, So, that is delegated authorization and that is frankly not an easy to understand concept, It's the first time I read the spec, or maybe the first three times, maybe even five times I read that spec, my head really hurt, at the end, But thing about it, that's a very, very common scenario given this multi-apps, multi-client architectures we are doing today. But sometimes you just need, well, just in quotation marks because authentication is a really tough to solve problem. But maybe you, you don't need this access token thing for your back-end, because maybe you don't want to talk to a back-end, at least not in the first place. You just want to know who the user is so you can, you know, personalize the UI for him Or control access to application features which are built into the application.And I guess we've all seen this button, Sign in with Facebook, Sign in with Google. And, you know, that is what many people really want to implement and do the delegated authorization step, maybe as a second thing later in the application. But first of all, they want to know who the user is. Now, OAuth is regularly abused for that. And I'm saying abused because OAuth on its own, like what, what you'll find in spec doesn't have enough features to do that securely. and, I, added here two links which are really important to read that tell you many of the details why OAuth is not good enough. And I will show the main things here as well, but this gives you more information.

problem-with-oauth-for-authentication oauth-2-o-and-sign-in-4

The Problems With OAuth2 Authentication

Let me quickly walk you through how OAuth2 if naively, or can be naively, used to do authentication. just to make it really clear. So, that is basically we are using the implicit flow here because it has more problems than the code flow.

OAUTH2 for AUTHENTICATION: REQUEST

GET /authorize?
     client_id=nativeapp&
     redirect_uri=http://localhost/cb&
     scope=signin&
     response_type=token&
     state=123

 UserInfo RS    Resource Owner Client -------> Authorization Server
 

But think of it like this. An application wants to authenticate the user. So, basically it does a round trip to the authorize endpoint of OAUth2 authorize endpoint, Says I'm the native app and they, they come up with some, you know, application defined scope for the authorization server nodes. This is not about authorization, This is about authentication, so some called the scope sign in, for example, That is you know, application defined. And the response type is a token meaning you get back a token for that user.

Now, since OAuth is an authorization protocol, what they are really asking for here is that the user gives access to a so-called user info endpoint, And the user info endpoint is the thing that knows about what's the user's name and, you know, his email address, and other stuff like that.

But the way people abuse OAuth is by saying, if I'm able to get an access token for the user info endpoint from the authorization server, the user must be authenticated somehow,

OAUTH2 FOR AUTHENTICATION: RESPONSE

GET /cb?
    access_token=abc&
    userid=123&
    expires_in=3600&
    state=123

UserInfo     Authorization server -----> Resource Owner Client

So, in the second step, we get back the access token for the user info endpoint.

OAUTH2 FOR AUTHENTICATION: ACCESSING USER DATA

GET /userinfo

Authorization: Bearer access_token

            ---------->
 UserInfo RS            Resource Owner Client
            <----------

And then the application uses the user info endpoint to fetch additional information about that user. Now, the problem here is that we didn't really do authentication at least not we ourselves, we just used some third party to give us an access token for an endpoint.

And the access token for the endpoint and the authentication event are not really correlated with each other,

So that leads to an interesting that, that leads to two interesting problems here really.

  • First of all the user info endpoint is always like an application specific thing. So, Facebook has its own user info endpoint. Google has its own user info endpoint. And Twitter has its own user info endpoint.So basically depending on with whom you want to do authentication, you need to understand the semantics of their specific user info endpoint, which is bad for compatibility. But the much more, the bigger problem here is a security problem.
THE PROBLEM

                                userid, accesstoken
1. User logs into malicious app <--------------------> Authorization server 
(app steals token)

So, think of this scenario here. You are basically using some malicious app, That might be a malicious web application. That might be a malicious application on your desktop or on your mobile device. And you start it and it says, like do you want to log in using Facebook, for example? I'm using Facebook here because that was a real problem with Facebook and you can read up on that in some of the links I provide you. And, you know, being a good, you know, a well education user, you say like, oh I won't give you know, this partially trusted application my Facebook password. Or, you know, some other password because, you know, I read about a threats on the Internet and I don't want to do that. So, what is application offers is you can login using Facebook, and you think like, oh, that's much better because now I type in my credentials into Facebook. And, you know, I have an existing, trusting relationship with Facebook, so that, that is okay. So, but what actually happens is as we've seen on the previous paragraph, now what actually happens is that with these credentials, the malicious application gets back an access token to your user info endpoint, okay?

THE PROBLEM


2. Malicious developer uses stolen access token <---Impersonated---> Source
  in legitimate app

So, now what this malicious application developer can do, is he goes to a legitimate application and just exchanges your valid access token or, or saying differently, he basically swaps out some access token with your access token. Now from the point of view of this valid application, this legitimate application, you've been impersonated, okay? So the application sees a token coming back from a trusted source, AK Facebook, for a trusted resource, AK the Facebook user endpoint.

And there's no way the application can distinguish between the token that resulted from what the user just typed in into Facebook authorization server and a forged token from you know, a forged transmission of credentials, okay? So, that is the big problem with OAuth for authentication. And that is what many, many of these OAuth providers suffer from.

So, as I said, Facebook had this problem, for example. And all of these companies that provide authentication based on OAuth had to add some protocol variations to it. Like extra token validation checks, for example, and so on. And it turned out that all of these protocol variations:

  • Made them incompatible
  • Brought them much closer to what we call OpenID Connect anyway.

So, they kind of implemented OpenID Connect you know, like, like in homegrown implementations to make it more secure. Now, the problem is now, that OAuth authentication is a very popular thing to do. And there are also, you know, like third party libraries, for example, that do away with all the incompatibility. So they know, for example, that you know, if the Facebook user info input works a little bit differently than the Google one. And they know that Facebook has added this extra, you know, protocol feature to make it more secure. Which basically, you know, brings us into a situation where we have to specifically write code for every OAuth provider to support their little flavor of authentication that they are providing. And also to use their extra security measures, because the raw OAuth flow is not good enough for authentication, as you've just seen.

OpenID Connect

What most of them are really doing, I just alluded to that, is something called OpenID Connect. So, when you go, for example, to the Google's API documentation page they said that yeah we use OAuth 2.0 for Login. But hold on, we are actually doing OpenID Connect but we, we're not calling it that way because we don't want to confuse people, okay? So, in other words OAuth2 itself is not good enough for authentication.

You can make it good enough for authentication, but that involves two things. One is the user info endpoint. That should be in some sort of standard format. And one is the introduction of an extra token type, and that is all specified by OpenID Connect.

OPEN CONNECT FLOWS

- OpenID Connect builds on top of OAuth2
 -- Authorization Code Flow
 -- Implict FLow

- Adds some new concepts
 -- ID Token
 -- UserInfo endpoint

- ..and some additional protocols, e.g
 -- discovery & dynamics registration
 -- session management

https://openid.net/connect/

So, OpenID Connect is a specification that is, that basically aims at the target that you don't need to know any specifics about the authentication provider

  • priori. Like you've just seen the screen that I've shown you from OAuth.io, they have support for 50 plus providers. The idea of Open, ID connect is that you don't need to have special case support for providers, because they are compatible with each other. So, Open, OpenID Connect builds on top of OAuth. They, they use the authorization code flow for server based applications and the implicit flow for client based applications. They add some, they add some constraints to OAuth2 as well. They, they add some new concepts like the user info endpoint I just talked about, and a new token type called the ID token which I'll show you in a second what that exactly is. And they added some, some other additional features which are missing from the OAuth core spec, like, for example, how can you discover an OpenID Connect provider. How can you a dynamically with an Open OpenID Connect provider. And also when we're talking about log in, we also need to talk about session management. So, for example, how do we log out again? And again, session management is not part at all of OAuth. So again, we need that that extra spec that is very similar to WS Federation, federated sign out or single sign out in, in the sample protocol for example, we just need these features.

OpenID Code Flow

So, let me show you the OpenID Connect Players.

                         OPENID CONNECT: THE PLAYERS

Identity-Provider Authorization-Endpoint Token-Endpoint UserInfo-EndPoint



        
           User Agent       Client


So you've seen here we have the user agent and the client. So, there's always a user agent involved. And either that's a browser, like a classical browser for Web applications, or it's of a few that is used in conjunction with a client application, like a native application or a, you know, a user agent based application.

                         OPENID CONNECT: 1A. AUTHORIZATION REQUEST

Identity-Provider Authorization-Endpoint Token-Endpoint UserInfo-EndPoint

                        ^ 
                        | GET /authorize?
                              client_id=webapp&
                        |     redirect_uri=https://webapp/cb&
                              scope=openid profile&
                        |     response_type=code&
                              state=123
                        |      
        
                      User Agent       Client


And you have the authorization endpoint and the token endpoint, and we know them already from OAuth. So, I said OpenID Connect is building on top of OAuth. So, when now an application like a client wants to initiate authentication, what it does is, it uses the standard OAuth messages to talk to an authorization endpoint. And the mindset here is really, do you want to allow the client to get access to your user profile and that includes authentication.

So, when we're doing a get request to the authorized endpoint. We are passing in the client ID. We are passing in the callback URI. And now what OAuth does is it defines scopes. So, an OpenID Connect request must start with a scope called OpenID. And then there are more things you can attach to that, like profile or e-mail, and I have a table later on that it shows you which types of values you can put in there.

But OpenID profile means that you get access to the user's profile, like first name, last name, email address, and these things. Then, response time equals code, meaning we're doing the code flow here, and the state parameters again for anti CSRF attacks.

Now, if the user is not authenticated already, then we need to make a round trip to the IDP. And again, just for reference here, these are the values of the scopes, like profile, email, address, phone and offline access, which means refresh token. Then again they are all specified in the OpenID Connect specification.

                         OPENID CONNECT: 1B: AUTHENTICATION

Identity-Provider Authorization-Endpoint Token-Endpoint UserInfo-EndPoint
        ^
        |
        |
        | 
      User Agent       Client


But much more importantly, if the user is not authenticated, now we are making the round trip to the identity provider, and again, the user types in his user name and password into a UI.

                         OPENID CONNECT: 1C CONSENT

Identity-Provider Authorization-Endpoint Token-Endpoint UserInfo-EndPoint

            --------------------------------------------
           |                                            | 
           | OPEN ID CONNECT                            |
           | Application WebApp asks                    |
           | for permission to access your profile      | 
           |                                            |
            --------------------------------------------

           User Agent       Client


Now when authentication has succeeded, the consent screen is shown, just like in extended OAuth. And as I said, the mindset here is really like, do you want to allow this application called WebApp access to your profile? And if you click Yes here, you get back the authorization code.

                         OPENID CONNECT: 1D AUTHORIZATION CODE

Identity-Provider Authorization-Endpoint Token-Endpoint UserInfo-EndPoint
                       |
                       | GET /cb?
                       |     code=abc&
                       V     state=123  
                     User Agent       Client

And then you use the authorization code to get a token response. So again, client authenticates with the token endpoint using his client id and secret passes in the authorization code.

                         OPENID CONNECT: 2A. TOKEN REQUEST

Identity-Provider Authorization-Endpoint Token-Endpoint UserInfo-EndPoint
                                                 ^
POST /token                                      |
    Authorization: Basic (client_id: secret)     |
    grant_type=authorization_code&               |
    authorization_code=abc&                      |
    redirect_uri=https://webapp/cb               |
                                                 |
                              User Agent       Client


And when all that security checks have succeeded we get back, the token response. And now, you see here, there's something special. For the access token is the standard OAuth access token, which is basically, which can be used to talk to the user info endpoint. So, nothing special here with regards to OAuth2. Just the refresh token, which gives you longer lived access to the user info endpoint. But, there's a special token now called the Id_token, and that one was missing from from the naive OAuth authentication implementations I showed you earlier.

Identity-Provider Authorization-Endpoint Token-Endpoint UserInfo-EndPoint
                                            |           
{                                           |
    "access_token" : "abc",                 |
    "id_token" : "uvw",                     |
    "expires_in" : "3600",                  |
    "token_type" : "Bearer",                |
    "refresh_token" : "xyz"                 |
}                                           | 
                                            |      
                                            V    
                         User Agent       Client

So the Id_token is really a token that is meant for the client. So the client the client's responsibility is now to immediately validate this Id_token. And what's inside of the ID token? Well, basically, there are four very important claims.

ID_TOKEN

JWT that contains claims about the authentication event
 - Issue(iss)
 - Subject(sub)
 - Audience (aud)
 - Expiration (exp)

Client must validate the ID token at this point
  • Where does the token come from? So, does it come from the OpenID Connect provider I just talked to.
  • The subject identifies the user.
  • The audience identifies for whom this token is for, and this token must be for the client that initiated the request. So, that allows the client to make sure that this token is actually for his own application.That was a feature that was missing in the naive implementation I showed you at the beginning.
  • And obviously an expiration, so, you know, these tokens cannot be, kept alive forever.
  • And the token is signed, obviously. And the client must validate the token, at this point.

So, once the client has validated the ID token, he knows that the response that came back from the authorization server was actually really for his own application and is basically a fresh interaction because there's an expiration value involved, and so on and so forth.

So basically this, this is very important extra feature that OpenID Connect adds on top of OAuth. So, we can really do authentication and not just, you know, assume once we get back some token from the authorization server, then authentication must have succeeded. But we cannot check it.

With the ID token, we can really validate that authentication succeeded. And that, you know, all, all of the players are the ones, are legitimate, and not some, you know, part got substituted in the process.

Okay, so now, once we know that the response was legitimate we already know that's a very important point here.

If you already know who the user is. That's the subject claim, And if, if that's all we need to know, like having a unique handle for that user, then we are done. But if we want to know more about a user, like his first name, last name, and so on, then you would go to user info endpoint. Would use the access token to access the user info endpoint and get back the additional profile information about the user.

                         OPENID CONNECT: 3A: UserInfo Request

Identity-Provider Authorization-Endpoint Token-Endpoint UserInfo-EndPoint
                                 Get /userinfo            ^
                                Authorization:            |
                                 Bearer access_token      |
                                                          |
                                                          |
                                       User Agent       Client


So that's OpenID Connect the authorization code flow. There's also an implicit flow, which works exactly the same as the implicit flow with OAuth 2. Just adding the ID token user info endpoint to the mix. And that's basically how OpenID Connect works.

And you can see then I deliberately draw these different players into separate boxes, like the identity provider, the authorization endpoint and so on because OpenID allows you to basically separate them. So, like the identity provider could be like an Intranet server whereas the authorization endpoint is accessible for from the Internet or the user info endpoint and so on. Which also allows you, or allows for architectures where the credential database is separate from the profile database, for example.

                         OPENID CONNECT: 3B: UserInfo Request
Identity-Provider Authorization-Endpoint Token-Endpoint UserInfo-EndPoint

                                 {                        |
                                  "sub": "248289761001"   |
                                   "name": "johe doe"     |
                                   "email": "xyz.eg.com"  |
                                  }                       |
                                                          V
                                       User Agent       Client

Okay, so, the last, really last step now would be the user info response. And again, this is a standardized format meaning the claims here, sub, name, email, they are, they are specified by OpenID Connect and the idea is that you simply get back a JSON encoded name value pair that includes the profile information.

Summary

  • OpenID connect standardizes how authentication with OAuth2 works

  • standard scopes and claims

  • token type is JWT

  • ID token

  • UserInfo endpoint

  • Goal is to allow a client to use an arbitrary OpenID Connect provider without code modifications

  • as opposed to how it works with homegrown OAuth2 authentication today

  • Not done yet, but "basic profile" pretty stable

  • Additional specs are under development

You've seen that OpenID Connect builds on top of OAuth2. Adds a number of extra features, like standard scopes and claims. Like, that the token type is fixed to chart. The ID token concept is something they added as a standard spec component, and the user info endpoint, And the idea as, as, as I said earlier, is that once this all is in place, your application, you know, can use arbitrary OpenID Connect providers to authenticate without you having to write extra or special case code. Like it works today with OAuth2 authentication because there's no standard how to do authentication with OAuth2.

OpenID Connect is not yet done. At least you know, there are a number of specs that make up OpenID Connect. One is called the basic profile. That is pretty stable now and it's expected to not change substantially anymore until the spec is done. There are additional specs which are still under heavy development especially the things like dynamic registration. Discovery, and session management, and so on. But, yeah, going forward, for Internet-based applications OpenID Connect is the new protocol to do authentication. And, in the long term, will replace WS Federation, WS-Trust, and, SAML 2.0

Clone this wiki locally