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.
Protocol Overview
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.
·
User-agent-based
application: this is the Rich Client profile where the code is running inside a
browser such as Javascript or Flash. In this case the client secret can be
compromised as it’s under the control of the user.
·
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.
Token Formats
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.
this is fascinating. i have joined your feed and stay up for in the hunt for more of your interesting post.
ReplyDeletewww.n8fan.net