OAuth2 & Google API Part II

In the first part of this article we have seen an introduction regard some basic concepts of this industry-standard framework called OAuth 2.0 (Open Authorization), a framework for authentication and authorization based on Tokens. We also went through an exercise of coding an example (using Gmail API Service and NodeJS) of one of its authorization grant type, the Authorization Code (a three-legged authentication scenario).

Now, at this Part II of our OAuth 2.0 journey, we are going to code an example of the two-legged authentication scenario using the Client Credentials grant type, one of those available by the specification. (See the little theoretical introduction of OAuth 2.0 framework at the Part I, in case you are not understanding very well what we are saying here).

Let’s use the Google Cloud Pub/Sub API Service to write our example, simulating our Application (playing the role of “Client” 3rd-Party Application), using the services provided by this API. Just for a matter of better understanding, and also in order you don’t need to go back to Part I and see what is (and the purpose of) the Google Cloud Pub/Sub API, we will put here the little presentation of it, the same written before:

CloudPubSub_IconGoogle Cloud Pub/Sub API Service (https://cloud.google.com/pubsub/)

  • This Google Cloud Service is an event base data stream system, useful to exchange information between consumers and providers in a stream using the very old (reliable and scalable) concept of messaging. It is not a surprise that the name of this cloud service is Pub/Sub. That rings a bell, doesn’t it?
    In order to be able to use this API Service, we need before require the authorization (as well perform the authentication) and for this happens, we will use the OAuth 2.0 through the Client Credentials authorization grant type, provided by the Google Cloud Pub/Sub API Service.
Client Credentials Authorization Grant Type
As stated before, now at this scenario we are going to use the two-legged authentication, a typical scenario where it is not possible, or not convenient, to have the presence of the “User” (Resource Owner), to give the consent of the authorization all the time, in a online manner. As in a Server-to-Server communication… imagine that part of your Application needs to interact with some API Service to perform a job, on behalf of the user, at some time that he/she is not present, a scheduled job for instance at three o’clock in the morning, or a event-based communication (that triggers some action when something happens, like a message being received in a queue).

It is worth to mention (again)…  as we said at the Part I regarding Client Credentials that:  this authorization grant type is typically used when the “Client” (3rd-Party Application) is also the “User” (Resource Owner), and it is performing an action on its own behalf, or…   is requesting access to protected resources based on an authorization previously agreed with the “API Server” (Authorization Server).

Revisiting the generic flow of this framework, in this scenario the communication would go like this:

Client_Credentials_Flow

Client_Credentials_Flow_Descrip

Having said all that, let’s use the Client Credentials authorization grant type in our example.

But, wait! Before dive into our code we have to perform some steps, in order that our Application be able to use the Client Credentials grant type, with the Google API Service. We need to create another type of credential at the Google Developer Console API, we need to create a Service Account.

  1. Open the Credentials Page of the Google Developers API Console: https://console.developers.google.com/apis/credentials (a logon to your account will be asked);
  2. Choose one of your projects at the Google API Console (on the top left corner, on the side of the Google APIs icon, you will find a Combo-box);
  3. Now, finally the Credentials: Click Create credentials → Service Account. And then…
    Create_ServiceAccount_1
  4. At the moment we finish the creation of the Service Account, a Private Key will be created automatically, and also a JSON file format will be downloaded, that besides our Private Key, will have other information regarding the Service Account Credential created for our Application. Keep in mind the localization (and also the security) of this file, we are going to need it later;
    Create_ServiceAccount_2
  5. The JSON File will have these information, the Private Key is the “key” of our identification with the Authorization Server;
    JSON_ServiceAccountPrivateKey.png

With all these steps already performed, we are (almost) done to start coding our sample and get our Application ready to use the OAuth 2.0 Client Credentials authorization grant type, in order to have access to the Google Cloud Pub/Sub Services.

I said almost done because, I remembered one more simple configuration thing we need to do. As mentioned we will use a Publish/Subscriber data event system, so let’s create a Topic and two subscribers that we are going to use at our sample application. Go to the Google Cloud Pub/Sub API Console at this address: https://console.cloud.google.com/cloudpubsub, create a Topic named “saques”, and two subscribers, named “ualter” and “junior”. You can change those name if you want, but the sample code available to download (as it is), will be using those by default. We’ll end with this configuration:

CloudAPIPubSub

The Sample!

Let’s check some key parts of our available solution, highlighting all the most important points where we interact with the Google API Service using the OAuth 2.0 implementation. In order to have an interesting user interface to see the application in action, we are going to use the practical set of graphics available by the JavaFX, but this will not be our main focus , as this is a complete and different subject of our main goal, and it would deserve its own separate article. But no worries, all the the whole code will be available to download, test it and see it running by itself.

Building this solution using Google API via Service Account, will result, in fact, in a concrete implementation that must follow this logic:

Flow_JWT_ServiceAccount

It is quite self-explanatory, the purpose, and the sequence of the events presented at this flow. That’s what our sample code must realize.

Create our Signed JWT to Call Google API Services

JSON Web Tokens (JWT), that’s an open industry standard (defined at RFC-7519 https://tools.ietf.org/html/rfc7519) method which the objective is representing the claims securely between two parties. Actually, we are going to use a JWS (JSON Web Signature) as we will need to sign this JSON Object with our claims (i.e. the JWT).
Think a JWT as an abstract class, that could be instantiate through one of the two concrete implementations: JWS (JSON Web Signature) or a JWE (JSON Web Encryption). Here we will use a JWS, but… from now on, for the sake of simplicity, let’s call it only JWT.
Remember the JSON that we downloaded?? When we created our Application’s Service Account at Developer Google API Console?? That’s right! Over there we can find our Private Key to sign our JWT. We will need of this to get our Access Token.

public String createTokenJWT(String apiScope) {
		RSAPrivateKey rsaPrivateKey = PublicPrivateKeysUtils.extractPrivateKeyFromString(appServiceAccount.getPrivateKey());
		
		ZonedDateTime timeBarcelona = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
		Date expiryDateTime         = Date.from(timeBarcelona.plusHours(1).toInstant());
		Date currentDateTime        = Date.from(timeBarcelona.toInstant());
		
		Claims claims = Jwts.claims();
		claims.put(Claims.ISSUER,    appServiceAccount.getIssuer());
		claims.put("scope",          apiScope);
		claims.put(Claims.AUDIENCE,  appServiceAccount.getAudience());
		claims.put(Claims.EXPIRATION, expiryDateTime.getTime() / 1000l);
		claims.put(Claims.ISSUED_AT,  currentDateTime.getTime() / 1000l);
		
		JwtBuilder jwtBuilder = Jwts.builder()
								.setClaims(claims)
								.signWith(SignatureAlgorithm.RS256, rsaPrivateKey);
		
		String compactJws = jwtBuilder.compact();
		return compactJws;
}
At the Listing 1, we have the method that generates our signed JWT, so we are
  • Line 145:
    • Creating a JWT with a duration of one hour;
  • Line 149 to 153
    • Setting our claims, following the rules of the Google’s API:
      • iss: the email address of the service account;
      • scope: A space-delimited list of the permissions that the application requests;
      • aud: A descriptor of the intended target of the assertion. When making an access token request this value is always https://www.googleapis.com/oauth2/v4/token;
      • exp: The expiration time of the assertion, specified as seconds since 00:00:00 UTC, January 1, 1970. This value has a maximum of 1 hour after the issued time;
      • iat: The time the assertion was issued, specified as seconds since 00:00:00 UTC, January 1, 1970;
  • Line 155:

The Java class GoogleAppServiceAccount is responsible to load (from JSON file) all the Service Account data, it carries all the information that we need to generate the JWT, including the Private Key. At Listing 1, an instance of this class is represented by the variable appServiceAccount, initialized at the GoogleJwtApiHandler constructor.

With the signed JWT generated, using our Service Account information (Private Key, Service Account Email Address), we can now call the Google API Server and asked for a Access Token.

public AccessToken retrieveAccessTokenToAPI(String jws) {
		StringBuffer postData = new StringBuffer();
		postData
		  .append("grant_type=").append(appServiceAccount.getGrantType())
		  .append("&assertion=").append(jws);
		
		
		HttpResponse response    = doHttpBasicPost(appServiceAccount.getTokenUri(), postData.toString());
		if ( response.getCode().isOk() ) {
			StringBuilder      json        = response.getContent();
			ObjectMapper       mapper      = new ObjectMapper();
			AccessToken        accessToken = null;
			try {
				accessToken = mapper.readValue(json.toString(), AccessToken.class);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			return accessToken;
		} else {
			LOG.error("Error {}-{} attemping retrieving the Access Token", response.getCode().getCode(), response.getCode().name());
			throw new RuntimeException("Error " + response.getCode().getCode() + "-" +  response.getCode().name());
		}
}
At the Listing 2, is the method responsible to retrieve the Access Token:
  • Line 97:
    • Adding to the request to the Google API Server, the Signed JWT, previously built as a parameter;
  • Line 100:
    • Sending the HTTP POST Request to the Google API Server URL to ask the Access Token;
  • Line 102 to 110:
    • If everything went well, we receive our Access Token in a JSON String. Using the good Jackson library, we convert this JSON to a valid Java Object to interact with the Access Token in this way, see it at the Listing 3.
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"access_token",
"expires_in",
"token_type"
})
public class AccessToken {
	
	@JsonProperty("access_token")
	private String accessToken;
	
	@JsonProperty("expires_in")
	private Integer expiresIn;
	
	@JsonProperty("token_type")
	private String tokenType;
	
}

Now we’ve got to the heart of the communication with the Google Pub/Sub API Services, the code in the class GooglePubSubApiHandler.java, that is, all the operations that call the others explained above, in order to perform the function of Publish a Message to the Topic “projects/ualter-oauth-sandbox/topics/saques”. Also, in this same class is present the Pulling operation, for the subscribers to read the arrived message at this topic. Let’s start with the publish operation.

public ResponsePublishTopic publishMessageOnTopic(String topic, ListMessages listMessages) {
		ResponsePublishTopic responsePublishTopic = null;
		
		final AtomicInteger countMessages = new AtomicInteger();
		listMessages.getMessages().forEach( m -> LOG.info("Publishing Message #{} - {} for Topic {}...",countMessages.incrementAndGet(),m.getDataDecoded(),topic));
		
		StringBuilder url = new StringBuilder(prepareUrl(GooglePubSubApiUtils.URL_PUBLISH_TOPIC).replaceAll("#topic#", topic));
		url.append("?access_token=")
		   .append(generateAccessToken().getAccessToken());
		
		ObjectMapper mapper = new ObjectMapper();
		String jsonPostData;
		try {
			jsonPostData = mapper.writeValueAsString(listMessages);
		} catch (JsonProcessingException e) {
			LOG.error(e.getMessage(), e);
			throw new RuntimeException(e);
		}
		
		HttpResponse response = doHttpJSONPost(url.toString(), jsonPostData.toString());
		if ( response.getCode().isOk() ) { 
			LOG.info("Total of {} Messages published to the Topic: {}",listMessages.getMessages().size(),topic);
			responsePublishTopic = response.convertResponseTo(ResponsePublishTopic.class);
			final AtomicInteger countResponse = new AtomicInteger();
			responsePublishTopic.getMessageIds().forEach(s -> {
				int    index = countResponse.incrementAndGet();
				String msg   = listMessages.getMessages().get(index-1).getDataDecoded();
				LOG.info("   ===> Message Id of the published message #{} - {} is: {}",index,msg,s);
			});
			
		} else {
			logError(response);
		}
		return responsePublishTopic;
}
At the Listing 4, finally we are going to publish our message, so here we are:
  • Line 79 to 81:
    • Preparing the URL to communication with the Google Pub/Sub API. For each one of the actions that we want to realize, as a RESTful Service, we have a proper URL syntax that we need to compose, in order to trigger the function. In our case is a Publish function. Here (https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/publish) you can find the documentation for this action, and all the others.
  • Line 86:
    • Transforming the List of Messages to be published, to a JSON string representation.
  • Line 92 to 105:
    • Communicating with the Google Pub/Sub API, using the URL and JSON previously prepared. According to the API documentation, the API Service get back a JSON list with the message’s IDs successfully published.
With this, we finished all the steps necessary for publishing a message at our Google Pub/Sub API Topic, called “saques”. The message is published there, available for the subscribers that we have created above to consume.

The steps to execute the operation of consuming the messages (GooglePubSubApiHandler.pullMessagesForSubscription) it is pretty much the same that we just have seen right now, we have to follow the same steps: generate the JWT, grab the Access Token, call the Google API and so on. Of course, what it is different it is the JSON Object types we use in question, the Google API Pub/Sub URL we call to, but… the rest it is equal, it is all available at the sample code provided, the link it is at the end of this article.

Basically, at it’s core, that’s what our sample realize is: use the OAuth 2.0 framework to get access to use a Google API Services, in this case a Google Cloud event data stream system. Remind that we are using the Client Credentials grant type, to obtain the authorization to interact with the API Services, representing ourselves through the Service Account created.

Before finishing the article at this point, only showing images of the JavaFX user interface built for the sample, let’s comment a little more about some characteristics of the sample built.

As we have an interaction and dependency between publisher (pushing messages) and subscribers (pulling messages) at the sample, in order to turn the things more interesting we have made use of the Java Concurrency API to start parallels threads representing our Subscribers listening constantly to the Topic, waiting for messages to arrive, as long as this featured is activated (ON/OFF toggle button).

So, with this purpose we are creating a Callable object to trigger the Pulling function at the method GooglePubSubApiHandler.pullMessagesForSubscription. This Callable object (where resides the function of Pulling messages) is wrapped by a FutureTask, that allows us to schedule/plan/delay its execution by submitting them to a daemon Thread later. At the Listing 5 we can see this in a few lines of code.
public FutureTask<ResponsePullMessagesSubscription> pullMessagesForSubscription(RequestPullMessagesSubscription request, boolean acknowledge) {
		CallablePullMessagesSubscription callable = new CallablePullMessagesSubscription(this.appServiceAccount,request, acknowledge);
		FutureTaskPullMessagesSubscription taskPullMessagesSubscription = new FutureTaskPullMessagesSubscription(callable);
		return taskPullMessagesSubscription;
}

To trigger this method, to receive and handle the FutureTask of Pulling Messages, in our JavaFX user interface Controller class, we create a JavaFX Task object that will be responsible for this action. Why do we have to do this? In order do not block the responsiveness of the JavaFX User Interface, that is, not get “freeze” while we are listening to the Topic (constantly pulling for messages), that’s why we use a JavaFX Task object to wrap this whole operation. At the image below we can have an idea of this logic:

Diagram_LoopJavaFXControllerTask

		this.futureTaskResponse = pubSubApiHandler.pullMessagesForSubscription(request, true);
		ExecutorService executor = Utils.createExecutorService("CONSUMER_" + NAMESUBS[subscriptionIndex] +  "-->PULLING");
		executor.execute(futureTaskResponse);

		try {
			// Let's put a timeout around of 5 minutes
			int times = 18000;
			int index = times;
			
			// Start Listening  
			while ( !returnImmediately ) {
				Thread.sleep(800);
				LOG.info("#{} Listening for a messages...", (times - index) + 1 );
				
				// Check if were found Messages analyzing if the Pull Task Messages were Done (finalized) 
				if ( futureTaskResponse.isDone() ) {
					// If were finalized the Task Pull Messages (messaged were found) show all of them
					ResponsePullMessagesSubscription response = futureTaskResponse.get();
					response.getReceivedMessages().forEach(m -> LOG.info(m.getMessage().getMessageId() + " - " + m.getMessage().getDataDecoded()));

					updateValue(response);
					
					// Get Back a Task Pull Messages listening during the rest of time for new Messages
					futureTaskResponse = pubSubApiHandler.pullMessagesForSubscription(request, true);
					executor.execute(futureTaskResponse);
				}
				
				if ( --index == 0 ) {
					futureTaskResponse.cancel(true);
					break;
				}
			}
			
			LOG.info("Listening for Pulling Messages, done!");
			executor.shutdownNow();
			
		} catch (InterruptedException | ExecutionException e) {
			throw new RuntimeException(e);
		}	

And that’s the code…

The code of our JavaFX Controller class that is managing everything is at the Listing 6:
  • Line 361 to 363:
    • Creating the FutureTask object to manage the Pull Messages function.
  • Line 371:
    • That’s the beginning of the while loop that is going to be running as long as the toggle button of the interface is set to ON. Actually, we are also setting here a timeout, maximum period of listening time around 5 minutes.
  • Line 381 to 385:
    • Here we are using a feature of the JavaFX Task to give a chance to our User Interface to rendering himself. We use the updateValue method, passing an object of our interest, in this case the response given by a FutureTask when its state changes to “done”. Following, we start again a new FutureTask to continues to listening.

Another thing that’s worth to mention, just for help understand better one more little thing, is: we are using a LogBack (https://logback.qos.ch/) implementation under the SLF4J (https://www.slf4j.org/), to print everything happening inside our application during its execution, because in this way we are able to see not only the “user’s final interaction”, but also the code’s behaviour (Threads, etc.). That’s why we inserted at his graphic interface a black box space (actually a TextArea component), where everything logged via SLF4J will be printed. In order to make this feasible, we had to write and configure our custom LogBack’s Appender. Everything is packed with the sample code.

Now that we have being through the most relevant parts of our sample application, let’s see it. The next image show how it looks like:

JavaFX_OAuthPuSubInAction

Conclusion

In this series of two articles we tried to get a better picture to understand better the industry-standard framework OAuth 2.0, a framework to help deal with authorization and authentication based on Tokens. At the first part, we saw some of its basic concepts them go through a sample coding to test the Authorization Code Grant Type. In this Part II we have met, mainly by practice, a sample of the Client Credentials Grant Type in action, a type that is suitable at enviroments of Server-to-Server communication. Hope you have enjoyed and in somehow also be useful now or in the future.

https://github.com/ualter/oauth2-sandbox