Contents


OAuth 2.0 clients in Java programming, Part 2

Client credentials grant

Comments

Content series:

This content is part # of # in the series: OAuth 2.0 clients in Java programming, Part 2

Stay tuned for additional content in this series.

This content is part of the series: OAuth 2.0 clients in Java programming, Part 2

Stay tuned for additional content in this series.

OAuth is an open standard for authorization that lets clients 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 user names and passwords. This series of articles adheres to the OAuth 2.0 authorization framework outlined in RFC6749. The complete OAuth 2.0 authorization framework as outlined under RFC 6749 can be found at the Internet Engineering Task Force website.

The authorization grant

The authorization grant is a credential that represents 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, and this access token is eventually sent along with the request to access a protected resource. OAuth 2.0 defines four grant types:

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

This four-part article series takes you through the implementation of an OAuth 2.0 client in Java™ programming using each of the grant types listed above. In this second part, I explain how to implement the client credentials grant. The article describes this grant in detail and explains the sample client code that you can use 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.

Client credentials grant

In this grant, a confidential client can request an access token from the authorization server using only its client credentials (or other supported means of authentication such as a public/private key pair). It is assumed that the client is requesting access to protected resources that are under its own control (client is the resource owner).

The flow illustrated in Figure 1 includes the following steps:

(A) The OAuth 2.0 client authenticates with the authorization server using its client credentials and requests for the access token from the token endpoint

(B) The authorization server authenticates the OAuth 2.0 client and validates the client credentials. If valid, the authorization server issues an access token.

Figure 1. Client credentials flow
Image showing the                     flow from the OAuth 2.0 client to the authorization server and back
Image showing the flow from the OAuth 2.0 client to the authorization server and back

Access token request

The access token request corresponds to step A, 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 "client_credentials"
  • client_id: REQUIRED. Client ID.
  • client_secret: REQUIRED. Client Secret/Password.
  • scope: OPTIONAL. The scope of the access request

Because the client authentication is being used as the authorization grant, no additional authorization is required. For example, the client makes the following HTTP request using transport-layer security:

Listing 1. Client HTTP request
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=myApp&client_secret=ab32vr

Access token response

The access token response corresponds to step B, as described in Figure 1. If the access token request is valid and is authorized, the authorization server returns the access token. A successful response is shown in Listing 2.

Listing 2. 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,
  "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 Outh2.0 client is available in the Download section in the OAuth2.0_client_credentials.zip file. The code is organized as a Java project, which can be imported into your Eclipse environment.

Prerequisites

You will need the Eclipse IDE for Java EE developers to set up your development environment and import the attached project. Download Eclipse from the Eclipse download page.

The project depends on the following JAR files:

  1. commons-codec-1.6.jar
  2. commons-logging-1.1.1.jar
  3. httpclient-4.2.5.jar
  4. httpclient-cache-4.2.5.jar
  5. httpcore-4.2.4.jar
  6. httpmime-4.2.5.jar
  7. json-simple-1.1.1.jar

The JAR files mentioned in points 1 to 6 can be found in the HttpComponents JAR file. It can be downloaded from the Apache HTTP Component project. The json-simple-1.1.1.jar file can be downloaded from the Simple JSON project page. Make sure you copy these JAR files to the lib folder of the Java project.

OAuth 2.0 client code

The OAuth 2.0 client discussed here implements the client credentials grant. In the subsequent parts of this tutorial series, the remaining grant types will be discussed, and the client code will be updated.

Input parameters

The input parameters for the client need to be supplied through the Oauth2Client.config properties file that is available under the resources folder in the project.

  • scope: This is an optional parameter. It represents the scope of the access request. The access token that is returned by the server has access to only those services mentioned in the scope.
  • grant_type: This needs to be set to client_credentials representing the client credentials grant.
  • 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 client credentials are exchanged for an access token as a part of this request.
  • authentication_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.

The client code is shown in Listing 3.

Listing 3. Client source code
//Load the properties file
Properties config = OauthUtils.getClientConfigProps(OauthConstants.CONFIG_FILE_PATH);
		
//Generate the OAuthDetails bean from the config properties file
Oauth2Details oauthDetails = OauthUtils.createOauthDetails(config);
		
//Validate Input
if(!OauthUtils.isValidInput(oauthDetails)){
 System.out.println("Please provide valid config properties to continue.");
 System.exit(0);
}
		
//Determine operation
if(oauthDetails.isAccessTokenRequest()){
  //Generate new Access token
  String accessToken = OauthUtils.getAccessToken(oauthDetails);
   if(OauthUtils.isValid(accessToken)){
      System.out.println("Successfully generated Access token for client_credentials grant_type: "+accessToken);
   }
   else{
    System.out.println("Could not generate Access token for client_credentials grant_type");
   }
}
		
else {
 //Access protected resource from server using OAuth2.0
 //Response from the resource server must be in Json or Urlencoded or xml
   System.out.println("Resource endpoint url: " + oauthDetails.getResourceServerUrl());
   System.out.println("Attempting to retrieve protected resource");
   OauthUtils.getProtectedResource(oauthDetails);
}

The client code in Listing 3 reads the input parameters supplied in the Oauth2Client.config file. It validates the values for client_id, client_secret, and authentication_server_url. If the resource server URL provided in the config file is valid, the client tries to retrieve the protected resource available at that URL. Otherwise, the client only makes 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 = oauthDetails.getResourceServerUrl();
				
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 == 401) {
	 // 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 == 401) {
			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 accepts the OauthDetails bean with the values retrieved from the config file.
  • As the name suggests, this method tries to retrieve a protected resource from the resource server. Hence, we create a simple HttpGet method.
  • To authenticate with the resource server, the access token needs to be sent as a part of the Authorization header.

    For 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 401, the access token used for authentication has probably expired or is invalid.
  • The next step is to regenerate the access token. (See 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.Client_ID,
 clientId));
 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 == 401) {
	System.out.println("Authorization
       server expects Basic authentication");
	// Add Basic Authorization header
	post.addHeader(
	OAuthConstants.AUTHORIZATION,
	getBasicAuthorizationHeader(oauthDetails.clientId,
	clientSecret));
	System.out.println("Retry with client credentials");
	post.releaseConnection();
	response = client.execute(post);
	code = response.getStatusLine().getStatusCode();
	
	if (code == 401) {
	throw new RuntimeException(
	"Could not retrieve access token for client: "
	clientId);
	   }
        }
      }
	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 client_id, client_secret, and, optionally, the scope as URL encoded parameters as part of the payload.
  • 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 client credentials.
  • OAuth 2.0 dictates 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 OAuth 2.0 client

This section explains how to set up an OAuth 2.0-compliant endpoint and test the client against it.

Testing the client with endpoints

This client has been successfully tested with Twitter and OAuth 2.0-compliant IBM endpoints such as IBM® Websphere® Application Server and IBM DataPower™.

Instructions for setting up an OAuth 2.0 endpoint on a Websphere application server can be found in "Enabling the OAuth service provider in WebSphere Application Server."

Running the client

Now that you have set up your OAuth 2.0-compliant server, you are ready to test your client and retrieve protected information from the server.

  • Import the Java project attached in this tutorial into your Eclipse workspace.
  • Download and copy the dependency JAR files to the project's lib folder.
  • Navigate to the resources/com/ibm/oauth/Oauth2Client.config file and fill in the values for the client_id, client_secret, and authorization_server URL.
  • Open Oauth2Client.java and run it in Eclipse.

Access token output

You should see the output in your console window as shown in Listing 6

Listing 6. Access token output
Resource server URL is null. Will assume request is for generating Access token
Validated Input

********** Response Received **********
  expires_in = 3600
  token_type = bearer
  scope =
  access_token = mc20Tn3Br8raUvCrBEap3VYMbErGXshjiXYFAwEB
Successfully generated Access token for client_credentials grant_type: mc20Tn3Br8raUvCrBEap3VYMbErGXshjiXYFAwEB

Retrieving user information from the server

Now that you have the access token, you can make a request to a web application hosted on a WebSphere Application Server that requires OAuth 2.0 authentication.

  • Update the Oauth2Client.confg file with the access token and populate the resource server URL property with the resource server URL that you want to test against.
  • Run Oauth2Client.java again.

You should see the output in your console window, as shown in Listing 7.

Listing 7. Retrieving user info
Resource endpoint url: https://localhost/protectedResource
Attempting to retrieve protected resource

********** Response Received **********
{
 "Author": "Varun Ojha",
 "Authenticatation": "Oauth2.0",
 "Result": "Success"
}

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

Conclusion

In this tutorial, you learned the basics of the OAuth client credentials. The tutorial described 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 users to import the project in their Eclipse workspace and start testing. Subsequent parts of this tutorial series will cover the remaining two grant types as outlined in the OAuth 2.0 authorization framework.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Security, Java development
ArticleID=987011
ArticleTitle=OAuth 2.0 clients in Java programming, Part 2: Client credentials grant
publish-date=10282014