I’ve spent a good amount of time trying to get to grips with OAuth 2.0 and OpenID Connect (OIDC). First you must get over the confusion that OAuth 2.0 isn’t the same, or backwards compatible with OAuth, and that OIDC isn’t the same, or compatible, with OpenID. Then you realise the unpicking doesn’t end there. This is because the two terms are often used interchangeably when they are two quite distinct concerns. It’s just that OIDC builds on top of OAuth. This makes understanding where they separate, and where they join, difficult.
In my research I found that articles were either very much focused on the use case from the perspective of the client application, focused on working with 3rd parties (Google, Facebook) or very detailed specifications for providers. What I couldn’t find was a high level understanding of the two, how they worked together, or how a typical enterprise would go about architecting for them.
My goal for this document is to provide just that: enough of a high level understanding so people can think about how OAuth 2.0 and OIDC could work in a typical enterprise context.
Lets start with OAuth 2.0. In as few words as possible OAuth only covers authorization (authz), not authentication (authn). Well, strictly speaking OAuth is not about authz in the traditional sense, it is more a mechanism for provide delegation via consent.
OAuth deals with mainly three things: flows, scopes and tokens (aka bearer tokens). OAuth divides differing responsibilities between four roles: Resource Owner (the user), Client (the app making calls), Resource Server (the API) and Authorization Server (the source that grants the token). Often the Resource Server and the Authorization Server are the same (e.g. Facebook or Google).
The token is the thing which represents proof of consent and what is ultimately used to validate access. Essentially the keys. There are two types of token an Access Token and a Refresh Token (which is optional). The Access Token is time limited and will expire and is what is used to validate access with. The optional Refresh Token is indefinite but can only be used to acquire new Access Tokens from the Authorization Server.
The Authorization Server is responsible for the management and issuing of tokens to the client. The token is opaque to the client. The token is simply sent to the Resource Server as part of the request and the Resource Server is responsible for validating the token and granting/denying access to the requested resource.
OAuth says nothing about the format of the Access Token. Therefore there needs to be some agreement between the Authorization Server and the Resource Server on how to validate the Access Token and its permissions.
Essentially a flow is the method you use to get you obtain proof of consent via co-ordination of the four roles. The flow changes depending on your use case (for example single page app vs Smart TV vs mobile app).
As a user you’re probably familiar with some aspects of some flows: when you click ‘Connect with Facebook/Google/Yahoo’, a pop-up appears, you login to the site (e.g. Facebook), click “Authorize”, get redirected etc. etc.
The main flows are divided into either three-legged (between Resource Owner, Client, Authorization Server) or two-legged (between client and sever):
- Authorization Code flow (three legged): for apps that can keep a secret: client/server web apps, mobile apps etc.
- Implicit flow (three legged): where a secret can’t be kept safe e.g. Single Page Apps
- Client Credentials flow (two legged): exchanges the client id and client secret for the tokens
- Resource Owner Password flow (two legged): exchanges the Resource Owner’s username and password for the tokens
And there are more flows being added, such as the Device Flow for things like Smart TVs etc. which have no easy input device.
The scopes represent the permissions needed to access resources (e.g. my email) from the Resource Server. The Resource Owner provides consent to the Authorization Server to delegate scopes to the Client. The user sees this as part of the flow when the Authorization Server lists the scopes the Client is requesting access to.
And that is a simple and quick overview of OAuth. Now onto OIDC:
Open ID Connect
OIDC is a standard to provide authentication to an application (the Relying Party) in the same way as SAML or WS-Federation. OIDC brings web scale to identity protocols by leveraging OAuth. It does this is a cunning way: by acting as a specialised Resource Server for user info (by providing a UserInfo endpoint) combined with a specialist Authorization Server which requires authentication. This specialist server is known as an OpenID Provider (OP).
OIDC introduces a few other concepts:
- Extends the existing flows: Authorization Code and Implicit
- Introduces a new three-legged flow: Hybrid which is a combination of the two. Hybrid is typically for SPAs with a web server back end. It allows the front end to use Implicit flow and the back end to use Authorization Code in co-ordination.
- New type of token called an ID Token (which represents the UserInfo).
- New roles: The OpenID Provider which uses an Identity Provider (IdP) to authenticate the Resource Owner. The Relying Party, which is the app (or client) which requires the end user to be authenticated_._
- New scopes (or claims)particular to UserInfo (openid, email, phone, profile, address). In fact Open ID is invoked using these scopes.
The OIDC scopes deserve a special mention. Essentially the client is requesting permission to specific scopes relevant to the users identity (email, phone, profile, address). The presence of scopes instruct the Authorization Server/OP that the client is requesting authentication. If this scope was missing then the authentication flow would not happen.
The openid scope is also special as its presence instructs the OP to return the ID Token.
If the client/Relying Party requests authorization with the openid scope then the OP’s response will contain an ID Token alongside the Access Token. ID Tokens contain metadata (the claims) about the user’s identity in a JSON Web Token (JWT). The ID Token is returned along with the access token by the OP which authorizes access to the UserInfo endpoint.
The same claims in the ID Token are available from the UserInfo endpoint (the ID Token is essentially a representation of the UserInfo).
In this way the ID Token acts as proof of authentication. The OpenID Provider is responsible for the management and issuing of ID Tokens to the Relying Party. The Relying Party is responsible for validating the ID Token and granting/denying access to itself.
As already mentioned OIDC is incredibly similar to SAML (bar a few low level details such as the role of cookies vs tokens) and is set to replace it. In fact a SAML app could easily be switched out to use OIDC without a user really noticing anything (or the dev team if you use something like Shibboleth).
Apart from the XML vs JSON argument because OIDC builds on top of OAuth it is far more flexible and scalable. Specifically with the ability to introduce new flows as new technologies come into play (which is something SAML suffered from), or enable dynamic registration (e.g. social login providers) and Bring Your Own Identity (BYOI). It is also advantageous as it simplifies the landscape by leveraging OAuth 2.0.
Open ID Connect vs OAuth 2.0
It is a common mistake to assume that OIDC is simply OAuth 2.0 with authentication added on. In fact OIDC is a means of providing authn by leveraging OAuth. OIDC is nothing but a spec for a specific type of OAuth Resource Server; it isn’t necessarily used for general OAuth authentication (say to APIs).
To understand this we need to run back through some basic concepts:
- OAuth uses Access Tokens as proof of consent
- OIDC uses ID Tokens as proof of identity
- OAuth uses scopes to represent permissions
- The OAuth Access Token is restricted to the scopes granted by the Authorization Server
- The OIDC UserInfoend point requires a valid Access Token with consent to one or more OIDC scopes
To put the above in context: in a vanilla OpenID Provider the Access Token will only grant access to the UserInfo endpoint (as that is all that the OIDC scopes grant).For API operations OAuth must validate against an Access Token which has consent to the scopes required to access resources provided by the Resource Server. But this is not what an OP provides.
Combining Open ID Connect and OAuth 2.0
So how do you move from OIDC authn to OAuth authz? This is where things get pretty murky. Like many things around OAuth and OIDC the specs are rather open to interpretation. This means there are many different patterns and practices to solve the same problems.Here are some of the various practices:
Authorization Server + OpenID Provider
Essentially the vanilla OAuth Authorization Server for APIs is extended to meet the OIDC requirements as well. Essentially by supporting the openid scope.This is the most common method, and the one Google uses. As an example, if you had a client which you wanted to ensure authn plus gain authz for access to Google Drive you simply request the scope=openid+https://www.
The challenges with this method is that the Authorization Server requires knowledge of all the legitimate scopes. Given that one of the fundamentals of OAuth/OIDC is to decentralise authn/authz this becomes a challenge to maintain.
This also assumes that your OP and Authentication Server are both within your control. As one of the benefits of OIDC is to Bring Your Own Identity (BYOI) the OP is likely provided by some other party which isn’t open to extending authorization to resources owned by your Resource Servers.
ID Token as Access Token
Because the ID Token encapsulates all necessary data to process an authentication it is tempting to assume that the ID Token could be used as an Access Token.
There are a number of problems with this approach:
- The ID Token represents authentication only, not authorization (thus undermining OAuth)
- The ID Token would have complete access: this breaks the principle of least privillage
- ID Token’s are long term tokens where as Access Tokens are meant to be very short term
- It overloads the semantics of the two tokens and mixes concerns that OAuth rightly separates
As recently as December 2015 the OAuth Working Group released their standards for OAuth 2.0 Token Exchange.
In this scenario your Authorization Server provides Token Exchange. This would allow a client to exchange the ID Token for an Access Token with the requested scopes. The Authorization Server simply needs to trust and verify the ID Token from the 3rd party OP.
There may be other techniques out there too. If so I’d be happy to hear them and get some critique and experience on how that went. But one thing’s for sure: OIDC and OAuth aren’t silver bullets and their implementation in the enterprise requires some very careful consideration.
Okta: How to secure your applications using OpenID
OpenID Connect - Okta Developer
End User Authentication with OAuth 2.0 — OAuth