Here’s my code. I’ve swapped in fake service account JSON credentials but have preserved all of the attributes of the JSON object and the general character set of each of the values. It generates a signed JWT for me but when I actually submit it with the cfhttp POST it just tells me { "error": "invalid_request", "error_description": "Bad Request" }
. Does anyone have any thoughts on what I might have wrong here? Thanks in advance for the help! The code is largely templated off of the firebase example here: Creating JWT in Coldfusion for google Service account
<cfscript>
variables.service_json = deserializeJSON(
'{
"type": "service_account",
"project_id": "my-project-123456",
"private_key_id": "11111aa22222bb33333cc44444dd55555ee66666",
"private_key": "-----BEGIN PRIVATE KEY-----naaaabbbbccccddddeeeeffff1111222233334444555566667777888899990000==n-----END PRIVATE KEY-----n",
"client_email": "my-service-account-email@my-project-123456.iam.gserviceaccount.com",
"client_id": "111222333444555666777",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/my-service-account-email%40my-project-123456.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}'
);
variables.timestamp = dateDiff("s", CreateDate(1970,1,1), now());
variables.timestampUTC = timestamp + 8*60*60; //add 8 hours to convert to utc
//generate jwt
variables.jwt_header = {
'alg': 'RS256',
'typ': 'JWT'
};
variables.jwt_header = serializeJSON(variables.jwt_header);
variables.jwt_header = toBase64(variables.jwt_header);
variables.jwt_claim = {
'iss': service_json.client_email,
'scope': 'https://www.googleapis.com/auth/analytics.readonly',
'aud': 'https://oauth2.googleapis.com/token',
'iat': timestampUTC,
'exp': (timestampUTC + 3600)
};
variables.jwt_claim = serializeJSON(variables.jwt_claim);
variables.jwt_claim = toBase64(variables.jwt_claim);
variables.jwt = variables.jwt_header & '.' & variables.jwt_claim;
//sign jwt
variables.keyText = reReplace( service_json.private_key, "-----(BEGIN|END)[^rn]+", "", "all" );
variables.keyText = trim( keyText );
variables.privateKeySpec = createObject( "java", "java.security.spec.PKCS8EncodedKeySpec" ).init(binaryDecode( variables.keyText, "base64" ));
variables.privateKey = createObject( "java", "java.security.KeyFactory" ).getInstance( javaCast( "string", "RSA" ) ).generatePrivate( privateKeySpec );
variables.signer = createObject( "java", "java.security.Signature" ).getInstance( javaCast( "string", 'SHA256withRSA' ));
variables.signer.initSign( variables.privateKey );
variables.signer.update( charsetDecode( variables.jwt, "utf-8" ) );
variables.signedBytes = signer.sign();
variables.signedBase64 = toBase64(signedBytes);
variables.jwt_signed = variables.jwt & '.' & variables.signedBase64;
</cfscript>
<cfhttp url="https://oauth2.googleapis.com/token" method="POST" result="res">
<cfhttpparam type="formfield" name="grant_type" value="urn:ietf:params:oauth:grant-type:jwt-bearer">
<cfhttpparam type="formfield" name="assertion" value="#variables.jwt_signed#">
</cfhttp>
<cfdump var="#variables.jwt_signed#">
<cfdump var="#res#">
I’ve tried a whole array of options but I need to use a Service Account, not an OAuth 2.0 Client ID. Within the Service Account approach I’ve tried using Ben Nadel’s https://github.com/bennadel/JSONWebTokens.cfc, but that required a public key which google oauth2 doesn’t provide. And so my best / closest attempt has been the code I have posted here.