I've read the following references and tried to use the signed JWT to get an access token from Google, but in fail:
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
How to obtain Google service account access token javascript
http://kjur.github.io/jsjws/tool_jwt.html
I'm wondering that my code is almost the same with the second link(How to obtain Google service account access token javascript) and still can't find out what's the problem with my code. That makes me so nervous.
The following is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<title>JWT(JSON Web Token) generator</title>
<script language="JavaScript" type="text/javascript" src="http://kjur.github.io/jsrsasign/jsrsasign-4.1.4-all-min.js"></script>
<script language="JavaScript" type="text/javascript" src="ext/json-sans-eval-min.js"></script>
<script language="JavaScript" type="text/javascript" src="jws-3.1.js"></script>
<script src="https://apis.google.com/js/client.js"></script>
<script language="JavaScript" type="text/javascript">
function requestAccessToken() {
var JWT = doSign();
var XHR = new XMLHttpRequest();
var urlEncodedData = "";
var urlEncodedDataPairs = [];
// urlEncodedDataPairs.push(encodeURIComponent("grant_type") + '=' + encodeURIComponent("urn:ietf:params:oauth:grant-type:jwt-bearer"));
// urlEncodedDataPairs.push(encodeURIComponent("assertion") + '=' + encodeURIComponent(JWT));
urlEncodedDataPairs.push("grant_type=" + encodeURIComponent("urn:ietf:params:oauth:grant-type:jwt-bearer"));
urlEncodedDataPairs.push("assertion=" + encodeURIComponent(JWT));
urlEncodedData = urlEncodedDataPairs.join('&').replace(/%20/g, '+');
function writeResponse(jsonResp, rawResp) {
document.myform.accessToken.value = rawResp;
}
var request = gapi.client.request({
'path': '/oauth2/v3/token',
'method': 'POST',
'headers': {"Content-Type": "application/x-www-form-urlencoded"},
'body': urlEncodedData
});
request.execute(writeResponse);
}
//JWS signature algorithm: SHA256withRSA with PKCS#8 plain private key(z4)
function doSign() {
var sClaim = JSON.stringify(getClaim());
var pHeader = {'alg': "RS256", 'typ': 'JWT'};
var sHeader = JSON.stringify(pHeader);
var key = myPrivateKeyPkcs8Pem;
var JWT = '';
JWT = KJUR.jws.JWS.sign(null, sHeader, sClaim, key);
document.myform.jwt.value = JWT;
return JWT;
}
function getClaim() {
var r = {};
r.iss = "<myserviceaccount>@developer.gserviceaccount.com";
r.scope = "https://www.googleapis.com/auth/drive.file";
r.aud = "https://www.googleapis.com/oauth2/v3/token";
r.exp = KJUR.jws.IntDate.get("now + 1hour");
r.iat = KJUR.jws.IntDate.get("now");
//http://kjur.github.io/jsjws/api/symbols/KJUR.jws.IntDate.html#.get
return r;
}
//skipped my private key
var myPrivateKeyPkcs8Pem = "" +
"-----BEGIN PRIVATE KEY-----\n" +
"MII...\n" +
"-----END PRIVATE KEY-----\n";
</script>
</head>
<body>
<form name="myform">
<h4>Press "Sign it" to generate signed JWT!</h4>
<input type="button" value="Sign it and get Access Token!" onClick="requestAccessToken();"/> <br/><br/>
<div>JWT:</div>
<textarea name="jwt" cols="65" rows="10"></textarea><br/><br/>
<div>Access Token:</div>
<textarea name="accessToken" cols="65" rows="10"></textarea><br/>
</form>
</body>
</html>
And the following is the headers:
<General>
Remote Address:XXX.XXX.XX.XX:443
Request URL:https://content.googleapis.com/oauth2/v3/token
Request Method:POST
Status Code:400 Bad Request
<Response Headers>
alternate-protocol:443:quic,p=1
cache-control:private, max-age=0
content-encoding:gzip
content-length:79
content-type:application/json; charset=UTF-8
date:Mon, 27 Apr 2015 20:55:59 GMT
expires:Mon, 27 Apr 2015 20:55:59 GMT
server:GSE
status:400 Bad Request
vary:X-Origin
vary:Origin
version:HTTP/1.1
x-content-type-options:nosniff
x-frame-options:SAMEORIGIN
x-xss-protection:1; mode=block
<Request Headers>
Provisional headers are shown
Content-Type:application/x-www-form-urlencoded
Origin:https://content.googleapis.com
Referer:https://content.googleapis.com/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.zh_TW.SI1fBy9C-R8.O%2Fm%3D__features__%2Fam%3DIQ%2Frt%3Dj%2Fd%3D1%2Ft%3Dzcms%2Frs%3DAGLTcCNsXEl0-sBYlv_cl9oHO7c1Y8AgBA
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36
X-ClientDetails:appVersion=5.0%20(Windows%20NT%206.1%3B%20WOW64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F42.0.2311.90%20Safari%2F537.36&platform=Win32&userAgent=Mozilla%2F5.0%20(Windows%20NT%206.1%3B%20WOW64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F42.0.2311.90%20Safari%2F537.36
X-Goog-Encode-Response-If-Executable:base64
X-JavaScript-User-Agent:google-api-javascript-client/1.1.0-beta
X-Origin:file://
X-Referer:file://
<Form Data>
view source
view URL encoded
grant_type:urn:ietf:params:oauth:grant-type:jwt-bearer
assertion:<my JWT>
The folowing is what I get from google:
{"gapiRequest":{"data":{"body":"{"error": "invalid_grant",
"error_description": "Bad Request"}",
"headers":{"date":"Mon, 27 Apr 2015 20:55:59 GMT",
"content-encoding":"gzip",
"expires":"Mon, 27 Apr 2015 20:55:59 GMT",
"server":"GSE",
"vary":"Origin, X-Origin",
"content-type":"application/json; charset=UTF-8",
"cache-control":"private, max-age=0",
"content-length":"79"},
"status":400,
"statusText":"Bad Request"}}}