Use-Case
This blog explains about using the JWT [JSON Web Tokens] to request for Access Tokens from the Service Providers who support JWT.
I will showcase this scenario by using Google API
What is this JWT [JSON Web Tokens] .............?
JWTs represent a set of claims as a JSON object that is encoded in a JWS and/or JWE structure.
The JWT Structure is mainly composed of three parts they are
Header.ClaimSet.Signature which are BASE64 Url Encoded.
For Further Information on JWT theory Refer the following Link :
http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13
Scenario
Create an Client ID by registering in the google apis console and download the keystore file.
Ensure to save this securely as downloading this again will result in the generation of an new file.
Header Claim:
Since Google uses the RS256 Hashing Mechanism to encrypt the keystore, we are setting the alg to RS256 and the type is set as JWT [JSON web Tokens]
{"alg":"RS256","typ":"JWT"}
Claim Set :
{
"iss":"
client_id of the application making the access token request@developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/userinfo.profile",
"aud":"https://accounts.google.com/o/oauth2/token",
"exp":1328554385,
"iat":1328550785
}
The scope given in the claim set basically gives the profile information of the client registered in the Google Apis console, but you can use the other Google developer Services like Google Cloud Storage or the Google Prediction API etc.
The fields exp and iat are the expiration and issuance time on when the jwt was created
Here the exp and iat play an major role as giving an invalid/outdated values may result in the Authentication failure.
Creating the Signature :
Use the following java code to generate the signature
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
public class BlogJavaCode {
public BlogJavaCode() {
super();
}
private String headerClaim="{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; //provide the above mentioned header claim
private String claimSet="{\n" +
"\"iss\":\" client_id of the application making the access token request@developer.gserviceaccount.com\",\n" +
"\"scope\":\"https://www.googleapis.com/auth/userinfo.profile\",\n" +
"\"aud\":\"https://accounts.google.com/o/oauth2/token\",\n" +
"\"exp\":"+generateEXP()+",\n" +
"\"iat\":"+generateIAT()+"\n" +
"}";
private long generateIAT()
{
long currentTime = System.currentTimeMillis();
long iat = (currentTime/1000);
return iat;
}
private long generateEXP()
{
long currentTime = System.currentTimeMillis();
long exp = (currentTime/1000+3600);
return exp;
}
/**
* This Method constructs the JWT token
* @return jwt string
*/
public String generateJWTToken()
{
String encodedHeaderClaim =null;
String encodedClaimset=null;
String tempStr =null;
byte[] signature = null;
String jwtToken= null;
try {
//Base64encoding of the Header Claim Set
encodedHeaderClaim = base64encoding(headerClaim.getBytes("UTF-8"));
//Base64encoding of the Claim Set
encodedClaimset=base64encoding(claimSet.trim().getBytes("UTF-8"));
//Temporary String needed to create the signature
tempStr = encodedHeaderClaim+"."+encodedClaimset;
//Load the key from the keystore file
PrivateKey serviceAccountPrivateKey = SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(),
new FileInputStream(""),
"notasecret", "privatekey", "notasecret");
//Get the UTF-based bytes for the tempStr as it needs to be signed
byte[] tempStrBytes = getbytesbasedforUtf8(tempStr);
//Constructing the Signature
signature = SecurityUtils.sign(SecurityUtils.getSha256WithRsaSignatureAlgorithm(), serviceAccountPrivateKey, tempStrBytes);
//The Final JWT String
jwtToken = tempStr + "." + base64encoding(signature);
} catch (UnsupportedEncodingException e) {
} catch (FileNotFoundException e) {
} catch (GeneralSecurityException | IOException e) {
}
return jwtToken;
}
public static String base64encoding(byte[] binaryData) {
return Base64.encodeBase64URLSafeString(binaryData);
}
public static byte[] getbytesbasedforUtf8(String string) {
return StringUtils.getBytesUtf8(string);
}
}
Making the Request :
Open an URL Connection append the following parameter along with the signature and make the post call as shown below
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=<SignatureObtainedFromtheAboveMethod>.