OAuth 2.0
Cloud CMS supports OAuth2 for server authorization. OAuth2 provides a secure and robust method for authenticating clients and users to the server. It's become well-adopted across the industry by other vendors including Facebook, Twitter and Salesforce.
We feel that OAuth2 is a best practice authorization mechanism for the applications that our customers build.
As we move forward, we intend to support additional authorization schemes as they are requested. However, we find that OAuth2 is a great foundation and best-of-breed today.
This section will provide a quick overview of OAuth2 and how it is supported by Cloud CMS within the API. If you would like all of the nitty-gritty details, you can browse over to the OAuth 2.0 Authorization Framework specification document and soak up the wisdom therein.
Clients and Users
Let's define the following:
- Client - the application (for example, a web site or a mobile application)
- User - the user who is using the client (for example, "joe smith")
OAuth2 describes a few strategies that the client and user can use to separately prove that they are who they say they are. These strategies are called "authorization flows".
While there are multiple OAuth2 authorization flows, the main one that you need to understand is the "authorization code" flow. The other flows are just simplified (and potentially less secure) variations of this flow. So let's take a look at an example.
Example: Steven Spielberg
Steven Spielberg and the Studio Lot Pass
Here's a really simple but fun example. It's based on a true story.
When Steven Spielberg was a young man, he took a tour of Universal Studios in Hollywood. During a bathroom break, he slipped away and happened to run into a film executive. They struck up a conversation and Steven mentioned some of his home-made films. The executive wrote him a pass so that Steven could return the next day. And the next day after that. For two weeks.
Each day, Steven would arrive to the front gate, greet the security guard, show him the pass and proceed into the studio lot.
Eventually, the film executive couldn't write any more passes and wished Steven the best of luck. So the next day, Steven arrived wearing a suit and tie. He waved to the guard. And the guard simply waved right back. So he walked right in. He proceeded to do that for two years! No one knew who he was. Everyone simply assumed that someone else knew who he was.
Steven earned a front-row seat and watched some of the great movie makers practice their craft. He was eventually thrown out during the filming of Alfred Hitchcock's famous film 'Torn Curtain'.
This is a pretty cool story. However, it's also demonstrates a security breach on a number of levels. For example, the pass he was issued should have expired after 2 weeks. And the security guard never checked whether he had lot rights.
OAuth2 splits the authorization flow into three distinct "legs". Each leg is a distinct isolated step whose participants are separated from other participants in the process. This makes it much more difficult for others to spoof the rights needed to access your data.
Let's take a look at how this sequence might play out if Universal Studios had an OAuth2-like framework in place:
Steven and the Guard Part I
- The Guard ('Resource Server') says, "No way kid, you have to have a pass to enter."
- Steven ('Client') says, "Can I request a pass? Come on, I'm Steven Spielberg! Here is my ID!"
- The Guard ('Resource Server') says, "That is fascinating. I don't care. Go to Customer Service and get a pass first."
First Leg - Client and Authorization Server
- Customer Service ('Authorization Server') asks, "Who is the pass going to be for?"
- Steven ('Client') says, "Steven Spielberg."
- Customer Service ('Authorization Server') takes the request for a pass and says, "Thanks, wait here..."
Second Leg - User and Authorization Server
- The Executive ('User') walks in and shows his ID to Customer Service ('Authorization Server').
- Customer Service ('Authorization Server') asks the Executive ("User"), "Are you sure you want to let Steven Spielberg onto the lot?"
- The Executive ('User') says, "Yeah, absolutely. I can see into the future. Someday, he is going to direct E.T."
Third Leg - Client and Authorization Server
- Steven ('Client') walks over to the next window and gives the authorization approval document to Customer Service ('Authorization Service').
- Customer Service ('Authorization Server') says, "This says that Steven Spielberg can get a pass. Are you Steven Spielberg? Prove it!"
- Steven ('Client') takes out his wallet and shows them his ID.
- Customer Service ('Authorization Server') says, "Alright. Here is a pass ('Access Token'). It's valid for two weeks."
Steven and the Guard Part II
- The Guard ('Resource Server') says, "Let me see your pass."
- Steven ('Client') says, "Here it is."
- The Guard ('Resource Server') checks to see whether the pass is still valid. It is, so he says, "Go on in!"
On subsequent visits, he simply needs to give the pass to the security guard. He doesn't need to go through this whole "OAuth dance" again unless his pass expires.
That's it. That's the basic three-legged authorization flow.
In addition, there exists a back-channel of communication so that the Guard can talk to Customer Service and vice versa. That way, they can detect whether Steven is trying to trick them (for example, if he tried walking up with a forged authorization approval document).
Also take notice that there are two signatures required - Steven's signature and the signature of the Executive. The Executive has to be sure which request he's authorizing (i.e. only Steven's) and so he requires Steven to first authorize his own request for a pass.
Authorization Flows
Cloud CMS supports the following authorization flows:
|Authorization Flow|Key|Description|
|Authorization Code|code|Full three-legged authorization (most secure) for untrusted client.This is what we saw in the Steven Spielberg example above.|
|Resource Owner Password|password|Two-legged for trusted client|
|Refresh Token|refresh|Authorization via a refresh token|
Authorization Code Flow
If you're building HTML5/JavaScript applications using browser-side technology, there are some limitations since you cannot securely embed the client secret into the HTML page or JS source. Cloud CMS provides "Open Driver" authentication which allows you to operate this flow without the client secret being exposed.
Here's how this works for the case where the client secret is contained in the flow:
First Leg
- The server responds with a redirect to a user login page. The redirect contains a request token in the URL.
Second Leg
- The server validates the identity of the user.
- The server prompts the user to approve the request for access to the resource.
- If the user approves the request, the server creates an "authorization code".
- The server responds with a redirect back to the original page. The redirect contains the authorization code in the URL.
Third Leg
- The application calls oauth/token with the code.
- The server authenticates the client and hands back an Access Token and Refresh Token.
- The Cloud CMS driver handles the third leg and beyond. You initialize the driver with the authorization code. The driver does the rest. It calls oauth/token and passes over the authorization code. It gets an access token. The driver then passes this access token across the wire with every call it makes going forward.
It also gets a refresh token. This token isn't used until the access token expires. After all, the access token isn't intended to live forward. When the access token expires, the driver will get back a 401. The driver then automatically employs the refresh authorization flow to acquire a new access token. Your code doesn't have to worry about any of this. The driver handles it.
Here is an example of an HTML page that kicks off an "authorization code" flow. When the flow completes, it will return to this page at which point we'll pick up the authorization code from the URL and feed it into the driver to sign on.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<script type="text/javascript" src="gitana.js"></script>
<script>
// assume the client key and secret are known
var clientKey = ...;
var clientSecret = ...;
// the uri to this page - we'll return back here with the code once the flow finishes
// this is something like - http://myserver:port/page.html
var redirectUri = window.location.protocol + "//" + window.location.hostname + ":"
+ window.location.port + window.location.pathname;
// the uri to request a token
// note that we're requesting the "api" scope (which is what the driver needs)
var authorizeUri = "/proxy/oauth/authorize?client_id=" + clientKey + "&redirect_uri=" + redirectUri + "&response_type=code&scope=api">
// here we use jQuery
$(document).ready(function() {
// if we receive an authorization code...
var code = Gitana.getCurrentQueryStringParameter("code");
if (code) {
console.log("Received authentication code: " + code);
// build the gitana driver
var gitana = new Gitana({ "clientId": clientKey, "clientSecret": clientSecret });
// authenticate with the code that we received
gitana.authenticate({ "code": code, "redirectUri": redirectUri }).then(function() {
console.log("Successfully authenticated");
});
}
// or we might have received an error
var error = Gitana.getCurrentQueryStringParameter("error");
if (error) {
console.log("Error: " + Gitana.getCurrentQueryStringparameter("error_description"));
}
// add in a link
$("#linkDiv").append("<a href='" + authorizeUri + "'>Click here to authorize</a>");
});
</script>
</head>
<body>
<div id="linkDiv"></div>
</body>
</html>
Resource Owner Password Flow
In terms of the example, this is kind of like if Steven Spielberg walked right up to the Customer Service center and said, "Hey look, I don't want to wait. Here is my ID. Here is the Executive's ID and a note from him saying he already approves. Just give me the pass."
The Customer Service folks technically have everything they need to do their job. However, this requires that they can trust Steven (as the Client) to have collected the IDs with their best interests in mind.
Here is the flow:
First Leg
- The application calls oauth/token and passes along the client key, client secret, username and password.
- The server validates the identity of the client and the user.
- If everything is okay, the server hands back an Access Token.
In order to use this flow, you must be very certain that the runtime environment for your code is secure. This flow requires the client secret and password to be made available within the client. Thus, it is imperative that these values not be exposed in clear text.
This flow should not be used for JavaScript or HTML5 applications running in the browser. Browser-based applications allow interested parties to "View Source" or Firebug the code. Any Client Secrets or Passwords can easily be snooped.
If you would like to use JavaScript or HTML5 in the browser, we suggest either the Authorization Code or Implicit Flows. If you must use the Resource Owner Password Flow, we recommend utilizing the Cloud CMS "Open Driver" strategy for enhancing your application security.
Here is an example of an HTML page that kicks off a "password" flow. Unlike the Authorization Code and Implicit Flows, this flow does not utilize redirects. The user never leaves the same page.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<script type="text/javascript" src="gitana.js"></script>
<script>
// assume the client key and secret are known
var clientKey = ...;
var clientSecret = ...;
// assume the username and password are known
var username = ...;
var password = ...;
// initialize the driver
var gitana = new Gitana({
"clientId": clientKey,
"clientSecret": clientSecret
});
gitana.authenticate({ "username": username, "password": password }).then(function() {
console.log("Successfully authenticated");
});
</script>
</head>
<body>
Move along, nothing to see here
</body>
</html>