Implement a generic and reusable OAuth 2.0 client in Java programming, Part 1: The resource owner password credentials grant

This multi-part series will help you develop a generic and reusable OAuth 2.0 client that can be used to interface with any OAuth 2.0–compliant server. Part 1 explains how to implement the resource owner password credentials grant.

Varun Ojha (varun.ojha@in.ibm.com), Staff Software Engineer, IBM

Photo of Varun OjhaVarun Ojha is a senior developer for WebSphere Cast Iron and works out of the IBM India software lab in Bangalore. He has seven years of experience in developing automation frameworks and in application integration and middleware.



07 January 2014

Overview

Extending security intelligence with big data solutions

Authorization frameworks are an excellent source of security intelligence. Are you getting the most out of your authorization infrastructure? Get the latest on IBM Security Intelligence and Big Data.

Download "Extending security intelligence with big data solutions."

OAuth is an open standard for authorization that enables clients to obtain access to protected server resources on behalf of a resource owner. The resource owner could be a different client or the end user. OAuth also helps end users authorize third-party access to their server resources without having to share their credentials, such as username and password. This series of articles adheres to the OAuth 2.0 authorization framework outlined in RFC 6749. The complete OAuth 2.0 authorization framework as outlined under RFC 6749 can be found at the Internet Engineering Task Force website (see Resources).


Authorization grant

The authorization grant is a credential representing the resource owner's authorization that can be used to access a protected resource. This credential is used by the client to obtain an access token. The access token is eventually sent along with the request to access a protected resource. OAuth 2.0 defines four grant types:

Sample client code

Download the sample client code discussed in this article.

  1. Authorization code
  2. Implicit
  3. Resource owner password credentials
  4. Client credentials

This article is the first in a four-part series that will walk you through the implementation of an OAuth 2.0 client in Java™ programming using each of the grant types listed above. In this first part, I will show you how to implement the resource owner password credentials grant. This article covers the grant in detail and explains the sample client code that can be used to interface with any OAuth 2.0–compliant server supporting this grant. By the end of the article you should have a complete understanding of the client implementation and be ready to download the sample client code for your own testing.


Resource owner password credentials grant

The resource owner password credentials grant type is viable when the resource owner has a high degree of trust in the client. This grant type is suitable for a client that can acquire the resource owner's user name and password. It is most useful for existing enterprise clients who use HTTP basic or digest authentication who want to migrate to Oauth. They can then migrate by using their existing credentials to generate an access token.

For example, Salesforce.com has added OAuth 2.0 as a authorization mechanism to their existing infrastructure. For existing clients to move to this authorization scheme, the resource owner password credentials grant will be most convenient, considering that they would require only existing account details such as the user name and password to retrieve an access token.

Figure 1. Resource owner password credentials flow
Figure showing resource owner password credentials flow

The flow illustrated in Figure 1 includes the following steps:

  1. The resource owner provides a trusted OAuth 2.0 client with its username and password.
  2. The OAuth 2.0 client makes an access token request to the authorization server's token endpoint by including the credentials received from the resource owner. When making the request, the OAuth 2.0 client authenticates with the authorization server using the credentials provided by the authorization server.
  3. The authorization server authenticates the OAuth 2.0 client and validates the resource owner credentials. If valid, the authorization server issues an access token.

Access token request

The access token request corresponds to the second step as described in Figure 1.

The client makes a request to the token endpoint (authorization server) with the following parameters sent using the application/x-www-form-urlencoded format.

  • grant_type: REQUIRED. Value must be set to "password"
  • username: REQUIRED. Resource owner user name.
  • password: REQUIRED. Resource owner password.
  • scope: OPTIONAL. The scope of the access request

If the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), the client must authenticate with the authorization server. For example, the client makes the following HTTP request using transport-layer security.

Listing 1. Authenticating with authorization server
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=varun&password=ab32vr

Access token response

Access token response corresponds to step C above, as described in Figure 1. If the access token request is valid and is authorized, the authorization server returns the access token and an optional refresh token. Listing 2 shows an example of a successful response.

Listing 2. Successful access token response
    HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}

If the request is not valid or is unauthorized, the authorization server returns an appropriate error message with code.


Setup

The sample OAuth 2.0 client is attached as a Java project that can be imported into your eclipse environment. You will need to download the third-party dependency JAR files to the lib folder in the Java project.

Dependency JAR files

The project uses the following JAR files:

  • commons-codec-1.6.jar
  • commons-logging-1.1.1.jar
  • httpclient-4.2.5.jar
  • httpclient-cache-4.2.5.jar
  • httpcore-4.2.4.jar
  • httpmime-4.2.5.jar
  • json-simple-1.1.1.jar

JAR files mentioned in the first six items can be found in the Http Components JAR files. See More downloads for links to download them and the json-simple-1.1.1.jar file. Make sure you copy these JAR files to the lib folder of the Java project available for download below.

Prerequisite

Download the Eclipse IDE for Java EE developers to set up your development environment and import the attached project. See More downloads for a link.


OAuth 2.0 client

The OAuth 2.0 client discussed here implements the resource owner password credentials grant. The subsequent parts of this series of articles will describe the remaining grant types and continue updating the client code.

Input parameters

The input parameters for the client need to be supplied using the Oauth2Client.config properties file that is available in the sample client code download (see Download).

  • scope: This is an optional parameter. It represents the scope of the access request. The access token that is returned by the server will have access to only those services mentioned in the scope.
  • grant_type: This needs to be set to "password" representing the resource owner password credentials grant.
  • username: The user name used to log into the resource server.
  • password: The password used to log into the resource server.
  • client_id: The client or consumer ID provided by the resource server when you register your app with it.
  • client_secret: The client or consumer secret provided by the resource server when you register your app with it.
  • access_token: The access token returned by the authorization server in response to a valid and authorized access token request. Your user name and password will be exchanged for an access token as a part of this request.
  • refresh_token: This is an optional parameter that can be returned by the authorization server in response to an access token request. However, most endpoints such as Salesforce, IBM Websphere® Application Server, and IBM Datapower do not return a refresh token for the resource owner password credentials grant. For this purpose, my client implementation will not consider the refresh token.
  • authenticatation_server_url: This represents the token endpoint. All requests for granting and regenerating access tokens need to be sent to this URL.
  • resource_server_url: This represents the URL of the resource server that needs to be contacted to access a protected resource by passing to it the access token in the authorization header.
Listing 3. Oauth2Client code
 Properties config = OAuthUtils.getClientConfigProps 	(OAuthConstants.CONFIG_FILE_PATH);
 String resourceServerUrl = config.getProperty(OAuthConstants.RESOURCE_SERVER_URL);      
 String username = config.getProperty(OAuthConstants.USERNAME);
 String password = config.getProperty(OAuthConstants.PASSWORD);
 String grantType = config.getProperty(OAuthConstants.GRANT_TYPE);
 String authenticationServerUrl = config
         .getProperty(OAuthConstants.AUTHENTICATION_SERVER_URL);
                
  if (!OAuthUtils.isValid(username)
    || !OAuthUtils.isValid(password)
    || !OAuthUtils.isValid(authenticationServerUrl)
    || !OAuthUtils.isValid(grantType)) {
  System.out
        .println("Please provide valid values for username, password,
                        authentication server url and grant type");
  System.exit(0);
   
   }
  

 if (!OAuthUtils.isValid(resourceServerUrl)) {
 // Resource server url is not valid.
 //Only retrieve the access token
 System.out.println("Retrieving Access Token");
 OAuth2Details oauthDetails = OAuthUtils.createOAuthDetails(config);
 String accessToken = OAuthUtils.getAccessToken(oauthDetails);
 System.out
 .println("Successfully retrieved Access token
  for Password Grant: " + accessToken);
 }
 else {
 // Response from the resource server must be in Json or
 //Urlencoded or xml
 System.out.println("Resource endpoint url: " + resourceServerUrl);
 System.out.println("Attempting to retrieve protected resource");
 OAuthUtils.getProtectedResource(config);
      }

The client code in Listing 3 reads the input parameters supplied in the Oauth2Client.config file. Valid values for username, password, authentication server url, and the grant type are mandatory. If the resource server URL provided in the configuration file is valid, the client tries to retrieve the protected resource available at that URL. Otherwise, the client makes only an access token request to the authorization server and retrieves the access token. The following section explains the code responsible for retrieving the protected resource and the access token.

Access protected resource

The code in Listing 4 demonstrates how to access a protected resource using the access token.

Listing 4. Access protected resource
String resourceURL =
config.getProperty(OAuthConstants.RESOURCE_SERVER_URL);
OAuth2Details oauthDetails = createOAuthDetails(config);
HttpGet get = new HttpGet(resourceURL);
get.addHeader(OAuthConstants.AUTHORIZATION,
getAuthorizationHeaderForAccessToken(oauthDetails
.getAccessToken()));
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = null;
int code = -1;
  try {
	response = client.execute(get);
	code = response.getStatusLine().getStatusCode();
	if (code >= 400) {
      // Access token is invalid or expired.
      // Regenerate the access token
      System.out.println("Access token is invalid
      or expired. Regenerating access token....");
      String accessToken = getAccessToken(oauthDetails);
      if (isValid(accessToken)) {
	// update the access token
      // System.out.println("New access token: " + accessToken);
      oauthDetails.setAccessToken(accessToken);
      get.removeHeaders(OAuthConstants.AUTHORIZATION);
      get.addHeader(OAuthConstants.AUTHORIZATION,
      getAuthorizationHeaderForAccessToken(oauthDetails
	.getAccessToken()));
      get.releaseConnection();
      response = client.execute(get);
      code = response.getStatusLine().getStatusCode();
	if (code >= 400) {
	throw new RuntimeException("Could not
  access protected resource.
  Server returned http code: "+ code);

     }

   } else {
	throw new RuntimeException("Could not
       regenerate access token");
	}

 }

   handleResponse(response);

Notes

  • This method populates the OauthDetails bean with the values retrieved from the configuration file.
  • As the name suggests, this method will try to retrieve a protected resource from the resource server, hence you create a simple HttpGet method.
  • To authenticate with the resource server, the access token will need to be sent as a part of the authorization header.

    Example: Authorization: Bearer accessTokenValue

  • Create a DefaultHttpClient to make the get request to the resource server.
  • If the response code received from the resource server is 403 or 401, the access token used for authentication has probably expired or is invalid.
  • The next step is to regenerate the access token (Listing 5).
  • After the access token is successfully regenerated, update the access token value in the OauthDetails bean. Replace the existing authorization header in the get method with the new access token value.
  • Now make another request to access the protected resource.
  • If the access token is valid and the resource server URL is correct, you should be able to see the contents of the response in the console.

Regenerate expired access token

The code in Listing 5 handles the regeneration of an expired access token.

Listing 5. Regenerate expired access token
 HttpPost post = new HttpPost(
 oauthDetails.getAuthenticationServerUrl());
 String clientId = oauthDetails.getClientId();
 String clientSecret = oauthDetails.getClientSecret();
 String scope = oauthDetails.getScope();

 List<BasicNameValuePair> parametersBody =
 new ArrayList<BasicNameValuePair>();
 parametersBody.add(new BasicNameValuePair(OAuthConstants.GRANT_TYPE,
 oauthDetails.getGrantType()));
 parametersBody.add(new BasicNameValuePair(OAuthConstants.USERNAME,
 oauthDetails.getUsername()));
 parametersBody.add(new BasicNameValuePair(OAuthConstants.PASSWORD,
 oauthDetails.getPassword()));

 if (isValid(clientId)) {
	parametersBody.add(new BasicNameValuePair
      (OAuthConstants.CLIENT_ID,clientId));
  }
 if (isValid(clientSecret)) {
	parametersBody.add(new BasicNameValuePair(
	OAuthConstants.CLIENT_SECRET, clientSecret));
  }
 if (isValid(scope)) {
	parametersBody.add(new BasicNameValuePair
      (OAuthConstants.SCOPE,scope));
  }

 DefaultHttpClient client = new DefaultHttpClient();
 HttpResponse response = null;
 String accessToken = null;
   try {
	post.setEntity(new UrlEncodedFormEntity(parametersBody,
       HTTP.UTF_8));
	
	response = client.execute(post);
	int code = response.getStatusLine().getStatusCode();
	if (code >= 400) {
	System.out.println("Authorization
       server expects Basic authentication");
	// Add Basic Authorization header
	post.addHeader(
	OAuthConstants.AUTHORIZATION,
	getBasicAuthorizationHeader(oauthDetails.getUsername(),
	oauthDetails.getPassword()));
	System.out.println("Retry with login credentials");
	post.releaseConnection();
	response = client.execute(post);
	code = response.getStatusLine().getStatusCode();
	if (code >= 400) {
	System.out.println("Retry with client credentials");
	post.removeHeaders(OAuthConstants.AUTHORIZATION);
	post.addHeader(
	OAuthConstants.AUTHORIZATION,
       getBasicAuthorizationHeader(
	 oauthDetails.getClientId(),
	oauthDetails.getClientSecret()));
	post.releaseConnection();
	response = client.execute(post);
	code = response.getStatusLine().getStatusCode();
	if (code >= 400) {
	throw new RuntimeException(
	"Could not retrieve access token for user: "
	oauthDetails.getUsername());
	   }
        }
      }
	Map<String, String> map = handleResponse(response);
	accessToken = map.get(OAuthConstants.ACCESS_TOKEN);
	} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
	} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
	}

	return accessToken;

Notes

  • This method generates an HttpPost request and hits the authentication server URL.
  • The Post request sends the username, password, and, optionally, the scope as URL-encoded parameters as part of the payload
  • Some authorization servers require that you send the client_id and client_secret as part of this request payload as well.
  • If the values for client_id, client_secret, and scope are not null, they will be sent as a part of the payload as well.
  • As per the OAuth 2.0 authorization framework, the client should set the authorization header with the client credentials or any other credentials provided by the server for authentication when making the access token request. But this is subject to the authorization server implementation. The client code makes the initial request without adding the basic authentication header. If the server returns an unauthorized response, the client subsequently tries by authenticating with the login and client credentials.
  • OAuth 2.0 dictates that the access token response be sent in JSON format. But for flexibility, I have added utility methods to handle an xml- or URL-encoded response from the server as well.

Testing the client

In this section, I discuss how to set up an OAuth 2.0–compliant endpoint and test the client against it.

Registering with Salesforce.com

Salesforce.com is a good use case for the resource owner password credentials grant. If a user has login credentials for Salesforce.com and wants to move his client to OAuth 2.0 authentication, all he needs to do is to register his app with Salesforce to retrieve client credentials. These client credentials, along with his existing login credentials, can now be used to retrieve an access token from the authorization server.

  1. If you have not previously registered with Salesforce.com, register now. See Resources.
  2. Click on Login and then click on Sign up for free.
  3. Complete the registration to receive your credentials.
  4. In addition to the user name and password, you will also receive a security token. The password that you provide for making an access token request needs to be a concatenation of your password and security token. (Example: password12312123).
  5. See Resources for a link to a useful article on how to create an app in salesforce.com.

Running the client

Now that you have completed registration with Salesforce.com, you are ready to test the client and retrieve protected information from their server.

  • Import the Java project discussed in this article into your eclipse workspace (see Resources).
  • Download and copy the dependency JAR files to the project's lib folder (see More downloads).
  • Navigate to the resources/com/ibm/oauth/Oauth2Client.config file and fill in the values for username, password (append security token), client_id, client_secret, and authorization server URL.
  • Open Oauth2Client.java and run it.

Access token output

You should see the following output in your console window.

Retrieving Access Token
encodedBytes dmVybi5vamhhQGdtYWlsL.......

********** Response Received **********
  instance_url = https://ap1.salesforce.com
  issued_at = 1380106995639
  signature = LtMjTrmoBbvVfZ6+qT5Un1UioHaV9KIOK7ayQTmJzCg=
  id = https://login.salesforce.com/id/00D90000000mQaYEAU/00590000001HCB7AAO
  access_token = 00D90000000mQaY!AQ8AQEn0rLDMvxrP9WgY3Blc.......
Successfully retrieved Access token for Password Grant: 00D90000000mQaY!AQ8AQEn0rLDMvxrP9WgY3Bl......

Retrieving user info from Salesforce.com

Now that you have the access token and ID, you can make a request to Salesforce.com to access your account info by authenticating using OAuth 2.0.

  • Update the Oauth2Client.confg file with the access token, and populate the resource server URL property with the value for id returned as a part of the response.
  • Run Oauth2Client.java again.

Output

You should see output similar to the following output in your console window.

Listing 6. Output
Resource endpoint URL: https://login.salesforce.com/id/00D90000000mQaYEAU/00590000001HCB7AAO
Attempting to retrieve protected resource
********** Response Received **********
photos = {"thumbnail":"https:\/\/c.ap1.content.force.com\/profilephoto\/005\/T","picture":"https:\/\
/c.ap1.content.force.com\/profilephoto\/005\/F"}
urls =
{"enterprise":"https:\/\/ap1.salesforce.com\/services\/Soap\/c\/{version}\/00D90000000mQaY","sobjects":
"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/sobjects\/","partner":"https:\/\
/ap1.salesforce.com\/services\/Soap\/u\/{version}\/00D90000000mQaY","search":"https:\/\
/ap1.salesforce.com\/services\/data\/v{version}\/search\/","query":"https:\/\/ap1.salesforce.com\
/services\/data\/v{version}\/query\/","users":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\
/chatter\/users","profile":"https:\/\/ap1.salesforce.com\/00590000001HCB7AAO","metadata":"https:\/\
/ap1.salesforce.com\/services\/Soap\/m\/{version}\/00D90000000mQaY","rest":"https:\/\/ap1.salesforce.com\
/services\/data\/v{version}\/","groups":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\
/chatter\/groups","feeds":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/chatter\/feeds",
"recent":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/recent\/","feed_items":"https:\/
\/ap1.salesforce.com\/services\/data\/v{version}\/chatter\/feed-items"}
  asserted_user = true
  active = true
  organization_id = 00D90000000mQaYEAU
  nick_name = vern.ojha1....
  display_name = varun ojha
  user_type = STANDARD
  user_id = ***********
  status = {"body":null,"created_date":null}
  last_name = ojha
  username = vern.ojha.....
  utcOffset = -28800000
  language = en_US
  locale = en_US
  first_name = varun
  last_modified_date = 2013-06-04T07:43:42.000+0000
  id = https://login.salesforce.com/id/00D90000000mQaYEAU/00590000001HCB7AAO
  email = vern.ojha@gmail.com

As you can see, you are able to successfully retrieve the user information by authenticating using OAuth 2.0. After the access token provided in the configuration file expires, the client automatically regenerates the access token and uses that to retrieve the protected resource available at the resource server URL.

Testing the client with IBM endpoints

This client has been successfully tested with OAuth 2.0–compliant IBM endpoints as well, namely IBM WebSphere Application Server and IBM Datapower. See Resources for a link to "Using OAuth: Enabling the OAuth service provider in WebSphere Application Server," a very good resource for setting up OAuth 2.0 on a WebSphere application server.

After you have set up OAuth 2.0 on your app server, the input required for the client is the same as demonstrated for Salesforce.com.


Conclusion

This article, Part 1 of an article series, explained the basics of the Resource Owner Password Credential Grant. It demonstrated how a generic OAuth 2.0 client in Java programming can be written to connect to multiple OAuth 2.0–compliant endpoints and retrieve protected resources from them. The sample client was attached as a Java project to quickly enable you to import the project in your Eclipse workspace and start testing. In subsequent parts of this series of articles, I will cover the remaining three grant types as outlined in the OAuth 2.0 authorization framework. The client code in subsequent parts will be updated to reflect these grant types along with features such as posting to a resource server and handling SSL.


Download

DescriptionNameSize
Sample client codeOAuth20.zip19KB

Resources

More downloads

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Security on developerWorks


  • Bluemix Developers Community

    Get samples, articles, product docs, and community resources to help build, deploy, and manage your cloud apps.

  • Security

    Pragmatic, intelligent, risk-based IT Security practices.

  • DevOps Services

    Software development in the cloud. Register today to create a project.

  • IBM evaluation software

    Evaluate IBM software and solutions, and transform challenges into opportunities.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Security
ArticleID=959474
ArticleTitle=Implement a generic and reusable OAuth 2.0 client in Java programming, Part 1: The resource owner password credentials grant
publish-date=01072014