5

I am trying to create a JSON Web Token in order to use it for making refresh token call with Google Analytics API access. I have taken service account approach.

As per this approach I need to :

  1. Create Service Account
  2. Add the Email Address created for the Analytics app with Google Analytics account.
  3. Download the priavte key file(.p12)
  4. Use this priavate key and email address for constructing JWT which will be subsequently used for making HTTP POST call to google auth server in order to get refresh token.

I am not sure whether my approach of creating JWT is correct or not. The sample available as JWT_Handler.java on the Google Code site talks about creating JWT with claim part and request payload only with header and signature part missing. This is confusing with googles guidelines for creating JWT for refresh token where the JWT involves three parts :

  1. JWT Header
  2. JWT Claim
  3. Signature

All the three parts are Base64Url encoded. I tried following code :

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Calendar;
import java.util.Enumeration;

import com.google.api.client.util.Base64;
import com.google.gson.JsonObject;
public class TestJWT {

private final static Charset UTF8_CHARSET = Charset.forName("UTF-8");
private static KeyStore myStore = null;
private static FileInputStream in_cert = null;
public static void main(String[] args) {
    PrivateKey privateKey = null;       
    try {
        in_cert = new FileInputStream(
                "D://Google Analytics//ClientLogin//Analytics//%$%%$%$%-privatekey.p12");

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }       
    try {
        myStore = KeyStore.getInstance("PKCS12");
        myStore.load(in_cert, "notasecret".toCharArray());
        String alias = "";       
        Enumeration objEnumeration = myStore.aliases();
        while (objEnumeration.hasMoreElements() == true) {
            alias = (String) objEnumeration.nextElement();              
            privateKey = (PrivateKey) myStore.getKey(alias,
                    "notasecret".toCharArray());
        }
    } catch (Exception e1) {
        e1.printStackTrace();
    }

    JsonObject header = new JsonObject();
    header.addProperty("alg", "RS256");
    header.addProperty("typ", "JWT");

    Calendar cal = Calendar.getInstance();      
    cal.set(1970, 01, 01);      
    String iat = Long.toString((System.currentTimeMillis() - cal.getTimeInMillis())/1000);
    String exp = Long.toString((System.currentTimeMillis() - cal.getTimeInMillis())/1000 + 60000L);

    JsonObject claim = new JsonObject();
    claim.addProperty("iss", "$$%$^%&^!%@#[email protected]");
    claim.addProperty("scope", "https://www.googleapis.com/auth/devstorage.readonly");
    claim.addProperty("aud", "https://accounts.google.com/o/oauth2/token");
    claim.addProperty("access_type", "offline");
    claim.addProperty("exp", exp);
    claim.addProperty("iat", iat);


    System.out.println("Header : " + header);
    String headerStr = header.toString();
    System.out.println("claim : " + claim);
    String claimStr = claim.toString();


    try {

        byte[] headerArr = headerStr.getBytes(UTF8_CHARSET);
        System.out.println(Base64.encodeBase64String(headerArr));

        byte[] claimArr = claimStr.getBytes(UTF8_CHARSET);
        System.out.println(Base64.encodeBase64String(claimArr));

        String inputStr = Base64.encodeBase64String(headerArr) + "." + Base64.encodeBase64String(claimArr);

        System.out.println("Input String : " + inputStr);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(inputStr.getBytes(UTF8_CHARSET));
        System.out.println("Sign : " + signature.sign());

        System.out.println("Base64url encoded sign : " + Base64.encodeBase64String(signature.sign()));

        System.out.println("Final JWT : " + Base64.encodeBase64String(headerArr) + "." + Base64.encodeBase64String(claimArr) + "." + Base64.encodeBase64String(signature.sign()));

    } catch (Exception e) {
        e.printStackTrace();
    }
}

}

1 Answer 1

2

Prathamesh, is this the same question as your other post? (Making Refresh Token Request In Java With JWT through a stand alone application - Not a Web App)

To clarify, signing a JWT using the P12 file will let you get an access token (not a refresh token). That's OK, because an access token is what you need to make a subsequent API call.

I strongly suggesting using Google's Java client library to construct the JWT and do the signing, of which you already pasted a good sample for in the other post:

GoogleCredential credentialGA = new GoogleCredential.Builder().setTransport(httpTransport)
        .setJsonFactory(JSON_FACTORY)
        .setServiceAccountId("$#$@#$#$#[email protected]")
        .setServiceAccountScopes(Collections.singleton(AnalyticsScopes.ANALYTICS_READONLY))
        .setServiceAccountPrivateKeyFromP12File(new File("$#$#$%$%$%$-privatekey.p12"))
        .build();
this.analytics = new Analytics.Builder(httpTransport, JSON_FACTORY, credentialGA).setApplicationName("Demo App").build();

Is there a specific reason you don't want to use the client library? It will take care of creating the JWT, signing it, sending it, buildng the service requests, adding authorization headers, refreshing the access token when it expires etc etc.

Sign up to request clarification or add additional context in comments.

4 Comments

To be very honest, i did not have any sample code to look for or any API usage doc for using Google Client library to generate JWT. I have on example for generating JWT in case of Google Wallet. That example do not show to generating JWT with Header for Google Analytics specific API.This was the reason i had to resort to creating this sample code. I had this bigger problem of getting refresh token, for which i thought creating a signed JWT was the first step.The other thread talks about the larger problem of mine. Sorry if created any confusion.
But would still appreciate if guidance provided on creating Signed JWT for Google Analytics.
OK, I think I might see where the confusion is. You should be able to use the same code to generate a signed JWT no matter which Google API you are trying to acccess. The key difference is to change the scopes that you are requesting, which it looks like you've already done. Can you confirm if the code above works for you? (And if not, what error you are receiving?)
One quick observation: Use 'encodeBase64URLSafeString' in place of 'encodeBase64String'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.