Introduction to OAuth 2.0
Like OpenID, OAuth is a decentralized protocol for the web space. However, while OpenID is about user authentication, OAuth is about web APIs authorization. To best understand OAuth, consider this scenario:
You have a web application that needs to access the Facebook timeline of its users. The application needs to call Facebook Web API to retrieve user timeline information. OAuth covers this scenario. The application redirects the user to Facebook where he/she is asked to log in; the mechanism by which a user logs in is irrelevant of OAuth (it could have been OpenID if Facebook supports it). Upon successful authentication, Facebook sends to the application an API key which the application then uses to authorize its access to Facebook’s API.
Although there are some apparent similarities between OpenID and OAuth, it’s also clear that there purpose is different:
· OpenID allows users to authenticate to multiple web sites using a single provider and thus negating the need of managing multiple credentials. But OpenID does not give the relying party the capability to access user resources from the provider. Note that this should not be confused with the protocol extension that allows the provider to send the relying party some profile information about the user.
· OAuth on the other hand, allow users to share their resources between different sites. How users do actually log in to the resource provider site or the resource consumer site is outside the scope of the protocol; actually they might even sign in using OpenID. The obvious advantage is that users do not have to duplicate their resources between different sites; for example, if users already use Flicker to store their images, then they can simple allow different sites to access these images without the need to duplicate. Even a possibly bigger advantage, is that users do not have to share their Flicker credentials with the site trying access the images.
First things first, OAuth 2.0 is more of a framework than a protocol. Although the specification does define step and interactions – which makes the case for protocol – it also defines an extensibility model and leaves a lot of details to be implemented as seen by different Authorization Servers. However, from this point on I will use the term ‘protocol’ to refer to OAuth 2.0 as this post does not address the extensibility features.
OAuth 2.0 defines the following roles:
· Client: the entity that wants to access a protected resource. In the previous example, this would be the web application that want to access a user’s Facebook timeline, or the site that wants to access a user’s Flicker images.
· Protected Resource: the resource that the Client wants to access. Again, this would be Facebook’s timeline or Flicker’s images
· Resource Server: The server holding the resources; i.e. Facebook or Flicker
· Authorization Server: the server that generates access tokens to Clients. This can be the same as the Resource Server.
The specification defines the following profiles, where each profile corresponds to a different client type:
· Web application: this is the more ‘traditional’ profile that we come to think about by default. The Client is a web application which the Resource Owner accesses using a browser. The Client makes the API calls to the Authorization Server and the user has no access to the client secret (discussed next) or the access token generated by the Authorization Server.
· Native application: this is the case of mobile apps where the code is running in user’s devices. It has the same security concerns of the user-agent-based flow.
The specification also defines a set of authorization flows which define how Clients get authorization from Resource Owners to access their Protected Resources. Each authorization flow is more suitable for one of the profiles discussed before (the specification call these “grant types”):
· Authorization code: most appropriate for the web application profile. In this flow, the Resource Owner grants his agreement for the Client to access his/her Protected Resources via a GUI. Once this happens, the Authorization Server redirects the browser back to the Client (the web application) with an authorization code in the query string. The Client then exchanges this code for an access token from the Authorization Server; for this to happen the Client must supply the Authorization Server with a previously generated “client_id” and “client_secret” during application registration. This flow is discussed in detail shortly.
· Implicit grant for user-agent-based applications: clearly this flow is suited to the user-agent-based profile. In this flow, again the Resource Owner is required to use the GUI to approve authorization; however, in this case the “intermediate” step of the authorization code is omitted and an access token is generated immediately.
· Resource owner password-based grant: the flows allows the Resource Owner to exchange a username/password combination for an access token. It is more suited to native application flow where – for example – a mobile application is written by the API provider itself.
· Client Credentials: this flow is suited for cases where the Client needs to access an API not on behalf of a specific Resource Owner, but rather on its own behalf; meaning the Client is the Resource Owner which needs for example to access specific application services.
More flows are defined as extensions to the specification:
· Device profile: enables OAuth 2.0 to be used in devices that has no web browsers
· SAML bearer assertion profile: allows exchanging SAML 2.0 tokens for OAuth 2.0 access tokens; useful in environments that already have SAML protocol-enabled Authorization Servers.
· JSON Web Token (JWT) bearer token profile: allows exchanging a JWT token for OAuth 2.0 access tokens; again useful for reusing existing infrastructures that utilize JWT
These extensions will be discussed briefly later in the post.
The next discussion is about the web application profile. The variants of the other profiles can be picked up in the spec documentation.
Step0: Client Registers with the Authorization Server
This is not a protocol step, but you can think of it as a pre-requisite for the protocol. The mechanism with which the Client registers at the Authorization Server is – again – outside the scope of the protocol.
The reason Clients register with the Authorization Server is to allow the server to identify API requests in a more secure manner. Upon successful registration, the Client is issued:
· A client identifier; a unique string knows as “client_id” to identify the Client when interacting with the server
· A secret used in the case of web application profile / authorization code flow, this secret – called “client_secret” – is used to exchange an authorization code for an access token; as described previously
Step1: Client Sends Authorization Request
The scenario starts when a Client (web application) wants to access a Protected Resource. The Client redirects the Resource Owner’s browser to the Authorization Server endpoint.
Before checking what will be in the request, let’s examine endpoints a bit:
An Authorization Server exposes two endpoints:
· Token endpoints: accessed programmatically by clients when sending access token requests
· End-user endpoints: page accessed by the browser where the Resource Owner confirms he/she trusts the Client to access the Protected Resource
The request includes:
· client_id: unique identifier of the Client; this is not a secret
· redirect_uri: the URL to navigate the browser to once step 2 is completed
Step2: Authorization Server Sends Back an Authorization Code
The Authorization Server asks the user if he/she agrees on sharing the Protected Resource with the Client (if the user is not already logged in, the Authorization Server will also prompt for authentication). As mentioned before, how the server manages authentication and asks the user for trust is out the scope of the protocol.
Now assuming the user was correctly authenticated and agreed on trusting the Client, the Authorization Server sends back to the redirect_uri of the Client (specified in the request) an authorization code which will be next used to obtain the actual access token.
Step3: Client Sends Access Token Request
Now that the Client has the authorization code, it sends an Access Token Request to the Authorization Server. The request includes:
· code: The authorization code received from the previous step
· redirect_url: the same value that was included in the request in step 1
· client_id: the unique client identifier
· client_secret: the secret key to authorize the API request
Step4: Authorization Server Sends Back Access Token
Authorization Server uses the redirect_url and sends back the actual access token. The response includes:
· access_token: the access token issues by the Authorization Server
· token_type: the type of the token; “bearer” by default. However, as mentioned before OAuth 2.0 is extensible and a separate spec exists for extensible token types, so the value here could vary.
Step5: Client Uses Access Token
So far, access token have been mentioned a lot but are yet to be clearly explained. So what are access tokens?
Be default, OAuth 2.0 does not require signatures (this is discussed next) and is content with “bearer tokens”. Bearer tokens are simple string-based tokens that grants its holder the required authorization for API usage; no additional signature is required to prove identity and detect tampering.
The Client can use this token in three ways when making API calls:
· Authorization Http header: this is preferred as headers are not cached.
· Query string parameter “access_token”
· HTML body
Signatures and Tokens
The biggest criticism for OAuth 2.0 is that it does not mandate the use of signatures. OAuth 2.0 authors believe that SSL/TLS is enough to provide protection and that by eliminating signatures, they have relieved developers from a complex requirement that is the source of implementation problems. OAuth 2.0 uses “bearer tokens” as a mechanism to provide authorization proof and says that signatures are not required to prove identity; it relies on SSL/TLS to provide secure transmission.
Protestors on the other hand say that while signatures are complex to implement, this is actually a good thing. Being complex means that only the best implementations will be adopted. SSL/TLS does not protect against API requests being send to fake endpoints, all these fake endpoints have to do is use a trusted certificate. These endpoint owners can then extract the credentials (client_id & client_secret) and reuse them to make API requests because identity of the sender is not guaranteed via signatures.
Another problem with SSL\TLS is that implementation libraries usually makes it easy for Client developers to disable certificate chain validation when making requests to Authorization Servers. As such Client developers must make some ‘standard’ checks on SSL certificates:
· Check that the hostname on the SSL certificate matches the URL
· Verify the certificate chain up to a trusted CA
A specification for MAC Access Authentication describes how to add signature support to OAuth 2.0. Authorization Servers that support MAC authentication generates a MAC key for the Client. This key can either by given to the Client during one of the communication steps described earlier, or can be done separately in some out of band mechanism such as during Client registration.
Now when making API requests, Clients use this key to generate a signature which is then verified by the Authorization Server.
So far, we have seen one type of tokens in action: the bearer token format. I also mentioned the MAC authentication specification which adds signature support for tokens regardless of their format.
In the very beginning, I mentioned the existence of specifications that allows utilizing existing token formats to be exchanged for OAuth 2.0 access tokens; I mentioned SAML bearer assertion profile and JWT bearer token profile. Let’s talk about this a bit.
Here is an excerpt from the JWT bearer token profile specification:
“The OAuth 2.0 Assertion Profile is an abstract extension to OAuth 2.0 that provides a general framework for the use of Assertions (a.k.a. Security Tokens) as client credentials and/or authorization grants with OAuth 2.0. This specification profiles the OAuth 2.0 Assertion Profile to define an extension grant type that uses a JSON Web Token (JWT) Bearer Token to request an OAuth 2.0 access token as well as for use as client credentials. The format and processing rules for the JWT defined in this specification are intentionally similar, though not identical, to those in the closely related SAML 2.0 Bearer Assertion Profiles for OAuth 2.0
This document defines how a JSON Web Token (JWT) Bearer Token can be used to request an access token when a client wishes to utilize an existing trust relationship, expressed through the semantics of (and digital signature calculated over) the JWT, without a direct user approval step at the authorization server. It also defines how a JWT can be used as a client authentication mechanism. The use of a security token for client authentication is orthogonal and separable from using a security token as an authorization grant and the two can be used either in combination or in isolation”
.NET Implementation in VS 2012
Just as was discussed in my post about OpenID, DotNetOpenAuth library is now released as part of VS 2012 ASP.NET templates:
Before diving into the code, you need to register the Client (localhost web app in this case) with the API provider which for this example will be Facebook. To do this create a Facebook Application by visiting https://developers.facebook.com/. Once done you will be given an App ID and App Secret, these map directly to client_id and client_password discussed before:
Now locate file AuthConfig.cs inside the App_Start folder and you can see that placeholders are already in place to enable your site for both OpenID and OAuth.
To add Facebook support to your support, uncomment the following lines and supply the App ID and App Secret; this prepares DotNetOpenAuth to communicate with Facebook as it now can identify itself using the id and gets authorized using the secret:
Switch to RegisterExternalLogin.aspx.cs and add the following line to store the access token returned by the Authorization Server (i.e. Facebook):
Session["accesstoken"] = authResult.ExtraData["accesstoken"];
Finally, in any page you want add the following code which uses the access token and makes an API request to get the feeds of the logged in user (more about the logged in user in a moment):
string acccessToken = (string)HttpContext.Current.Session["accesstoken"];
FacebookClient appp = new FacebookClient(acccessToken);
dynamic myPages = appp.Get("/me/feed");
What is “FacebookClient”? I have used Facebook C# SDK (http://csharpsdk.org/) which provides an easy wrapper to talk to Facebook API.
Now launch the application. Chose to login using Facebook. Now let’s think about this for a moment: we have established that OAuth is an API authorization protocol and not an authentication protocol. So how Clients authentication its Users (Resource Owners) are outside the scope of OAuth. Resource Owners might authentication using any mechanism; ‘traditional’ username/password, X.509 certificate, or event OpenID.
Moreover, we have discussed that Users are required to authorize API access using a GUI in the web application profile. Now how each API provider handles this differs from one provider to another, also each Client might have a customized handling for this. Some implementations might ask for this authorization right before the API request, or it can be the first step and the response is saved somehow…the point is that these are customized behaviors and again have nothing to do with the protocol itself as long the final outcome is achieved.
After authenticating to Facebook, the Client library has actually quietly – under the covers – gone over steps 1 and 2 discussed before (Facebook uses its own Facebook Connect protocol for both authentication and generating the OAuth 2.0 access token in a single step). Fire Fiddler and observe that the access token has been granted for the Client:
Now, you can use the access token to make the API request, as shown before; and here is the Fiddler data again:
A Word about OpenID Connect
The previous article discussed OpenID 2.0 while this article delved into OAuth 2.0, the former deals with unifying authentication for one site against different providers, while the other adds API authorization support. Now wouldn’t it be great if there is a single protocol that handles both?
Meet OpenID Connect.
OpenID Connect is built on top of OAuth 2.0 to ‘standardize’ API authorization across multiple providers much like OpenID 2.0 standardize authentication across multiple providers; only it does both: OAuth 2.0 is the authorization protocol; OpenID Connect adds authentication to it.
So OpenID Connect will actually – with time – replace both OpenID 2.0 and OAuth 2.0.
OpenID Connect will be a topic of a future post.