Posted by & filed under APIs, groovy, mobile, oauth2, REST.

The third OAuth2 flow that we’ll cover as part of this series is the Resource Owner Password Flow. We’ve covered the OAuth2 Authorization Grant Flow and the OAuth2 Implicit Flow so far. We’ve also seen how client applications can refresh expired access tokens.

The Resource Owner Password Flow is really pretty simple, as it allows the client to exchange a user’s username and password for an access token. Woah….. what? Yes, it means the client applications, let’s say an Android app will really need ask for the username and password. Wasn’t OAuth2 all about not getting hold of the username and password from a client app perspective? Yes, to some degree. Fortunately, this is a flow that is not for intended to be used for and by 3rd party app developers. The perfect app using this flow is a first-party app, e.g. the “official” Android app for your API. This means you typically have a contractual agreement between the owner of the API and whoever creates the official app(s) for your API. In this case you can trust the client code and asking for username and password becomes less an issue.

Now that the trust issue seems to be solved, there’s still one thing that an API provider should not do wrong when it is offering the OAuth2 Resource Owner Password Flow: offer no refresh tokens. If the access tokens given out via this flow are not combined with refresh tokesn, it means the client application does not only have to pass the username and password, it also has to remember the credentials. By offering refresh tokens, the client will only have to remember the tokens and this is a way better idea than storing the user’s username and password.

Here at hybris, we’ve been using Basic Authentication over HTTPS for the OCC Web Services, our commerce-driven RESTful web services. This was a no-brainer’s decision as API clients are typically contractually controlled and the combination of HTTPS and Basic Auth is pretty simple. While we will still support this old authentication protocol with a few changes to a Spring XML configuration file, we decided to make OAuth2 Resource Owner Password flow the auth protocol standar for API access in future. The benefit that OAuth2 still provides is that the client does not have to remember the username and password, which is better for security even though it is a small step forward (agreed).

Of course, OAuth2 and also our OAuth2 implementation offers the other auth flows as well, which now opens our API for other clients such as HTML5 Clients or remote frontend web apps for example.

So let’s look at the flow diagram from the OAuth2 spec for the Resource Owner Password Flow:

Short, isn’t it :-)

(A) The client will first need to ask for a user’s username and password. In step A, the user will then enter this information directly into the client app. Again it should be noted here, that the user will need to have a way to identify the app as being the “official” app that he can trust.

(B) Next, the client (app) makes a request to the Authorization Server, e.g. the /oauth/token endpoint. There are two ways the client_id and client_secret can be sent along: either in a regular Basic Authentication request header, or as part of the parameters passed in the request payload (the body of the request). Before we look at examples for both, here is the list of parameters that need to be passed:

  • client_id and client_secret: either passed as parameters client_id and client_secret, or as a Basic Authentication header. Basic Authentication means, that client_id and client_secret are treated as username and password, concatenated using a “:” colon and then Base64 encoded. This value is then used as part of the Authorization request header, e.g.:
    Authorization: Basic <Base64-encoded username:password>
  • username and password: credentials for the resource owner, the user’s real credentials
  • grant_type: needs to be set to ‘password’ for this flow

Let’s look at the code:

import com.google.appengine.api.urlfetch.*
import groovy.json.*
import java.net.URLEncoder

def client_id = 'mobile_android'
def client_secret = 'secret'

if (!params.username)
{
	out << "No username given..."
	return
}

if (!params.password)
{
	out << "No password given..."
	return
}

def username = URLEncoder.encode(params.username, 'UTF-8')
def password = URLEncoder.encode(params.password, 'UTF-8')

HTTPResponse res
URL tokenURL = "http://localhost:9001/rest/oauth/token".toURL()

if (params.basic)
{
//direct exchange of username and password for access token
def headers = [Authorization:"Basic ${"${client_id}:${client_secret}".toString().bytes.encodeBase64().toString()}"]
res = tokenURL.post(deadline: 30, headers: headers, payload:"grant_type=password&username=${username}&password=${password}".getBytes())
}
else
{
	//direct exchange of username and password for access token
	res = tokenURL.post(deadline: 30,  payload:"client_id=${client_id}&client_secret=${client_secret}&grant_type=password&username=${username}&password=${password}".getBytes())
}

out << res.text

Again, our client code is a Gaelyk controller written in Groovy. This is if course only for demonstration purposes. The code would typically be not part of a server-side web app (for a web app, we’d use the way more appropriate Authorization Grant Flow). But I guess it shows nicely how the single request against the Authorization server is performed.

First, client_id and client_secret need to be known to the code issueing the request. Username and password is in our case passed via parameters and would in a real world scenario be entered into a form via the app’s UI. Depending on the basic parameter, we either pass the username and password in a HTTP Post request as the Authorization header or as part of the parameters in the body of the request.

Our sample code simply prints the response, which shall be a JSON-formatted document like this:

{"access_token":"f2288c2b-1d08-4aac-a210-d62c0901f915","token_type":"bearer","refresh_token":"3f94522d-5a5a-4a22-bc85-f5f5a56920b4","expires_in":43199}

You’ve seen this response before, for example in the Authorization Grant Flow. Because our server issued a refresh token, there is no need for the client app to remember the username and password. It can simply store the access and refresh tokens along with the expiry information to know when it should proactively refresh the acces token via the refresh token.

Next up: the OAuth2 Client Credentials Flow – which is in many cases not super important, also kind of special. We’ll cover it for the sake of completeness. We’ll finally also cover the complete Spring Security config for OAuth2, which I guess will be super interesting for a few.

4 Responses to “OAuth2: The Resource Owner Password Flow”

  1. Matt

    Do you have an example of the code that actually creates the Access token? In other words, what happens during the post call to the token endpoint?

    Reply
  2. Robert

    Thanks for the great series of blog. It really helped me a lot on understanding the logic flow for oAuth. I have one question though. What do you suggest for generating client-id and client-secret for first party-app? Thanks.

    Reply
    • hansamann

      Hi Robert, when you look at Foursquare or Facebook, the client_id and secret are typically some kind of hashes. I would suggest to use a non-deterministic generator and then hash using SHA-1 for example. I just found this here online: http://www.joeswebtools.com/security/sha1-hash-generator/.

      If you do not need to have tens of clients connecting, you can come up with the “random” client_id and secrets yourself manually I would say. Choose a sentence, word or paragraphc and put it into the SHA1 to generate a id or secret. I’d love to hear other’s experiences with this regard though.

      Reply

Trackbacks/Pingbacks

  1.  Trying out OAuth2 via CURL | HyTech
  2.  OAuth: the Client Credentials Flow | HyTech
  3.  Austen McDonald • OAuth 2 with Resource Owner Password Credentials Flow (username and password)
  4.  HyTech – OAuth2: server side implementation using the Spring Security OAuth2 module

Leave a Reply

  • (will not be published)