我尝试在scriptr.io上创建一个脚本,创建JWT/JWS以发送到Google的令牌端点,以获得auth_token
我的服务帐户。我正在使用CryptoJS library进行加密。我能够生成JWT的所有3个部分,但是这样做我做错了。我相信它与字符串的三个部分中的最后一部分(因此,签名部分)有关,但我可能是错的。
var cryptoJs = {};
cryptoJs['SHA256'] = require('CryptoJS/rollups/sha256.js').CryptoJS.SHA256
var pHeader = {"alg":"RS256","typ":"JWT"}
var sHeader = JSON.stringify(pHeader);
var encodedHeader = Base64EncodeUrl(btoa(sHeader));
console.log("encodedHeader: " + encodedHeader);
var now = new Date();
var oneHourExpiration = ((now.getTime()-now.getMilliseconds())/1000)+3000;//3000, not 3600 which is 1 hour
var pClaim = {};
pClaim.iss = "-------@---iam.gserviceaccount.com";
pClaim.scope = "https://www.googleapis.com/auth/spreadsheets";
pClaim.aud = "https://www.googleapis.com/oauth2/v3/token";
pClaim.exp = oneHourExpiration;
pClaim.iat = Math.floor(Date.now()/1000);
console.log("exp: " + pClaim.exp);
console.log("iat: " + pClaim.iat);
var sClaim = JSON.stringify(pClaim);
var encodedClaim = Base64EncodeUrl(btoa(sClaim));
console.log("encodedClaim: " + encodedClaim);
var byteArray = encodedHeader + "." + encodedClaim;
console.log("byteArray: " + byteArray);
var secret = "-----BEGIN PRIVATE KEY-----\n.....MIIE.....=\n-----END PRIVATE KEY-----\n";
var signature = cryptoJs.SHA256(byteArray, secret);
var encodedSignature = Base64EncodeUrl(btoa(signature));
console.log("Encoded Signature: " + encodedSignature);
var sJWS = byteArray + "." + encodedSignature;
console.log("JWT: " + sJWS);
function Base64EncodeUrl(str){
return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
}
var http = require("http");
var requestObject = {
"url": "https://www.googleapis.com/oauth2/v3/token",
"method": "POST",
"headers": {"Content-Type":"application/x-www-form-urlencoded"},
"params": {"grant_type":"urn:ietf:params:oauth:grant-type:jwt-bearer","assertion":sJWS}
}
var response = http.request(requestObject);
var responseBodyStr = response.body;
console.log(responseBodyStr);
var token = JSON.parse(responseBodyStr.access_token);
console.log(token);
当我使用JWT将请求发送到令牌端点时,我得到以下响应
{
"error": "invalid_grant",
"error_description": "Invalid JWT Signature."
}
知道我哪里出错了吗?有人可以帮我正确格式化JWT,这样我就能获得一个令牌吗?
答案 0 :(得分:1)
使用的函数是做哈希,而不是数字签名
var signature = cryptoJs.SHA256(byteArray, secret);
不支持使用RSA私钥的数字签名。查看CryptoJS
主存储库中的注释<强>不活动强>
CryptoJS是我在业余时间享受和工作的项目,但是 不幸的是,我的9比5没有给我留下尽可能多的空闲时间 以前。我仍然希望将来继续改进它,但我 不能说什么时候会的。如果您发现CryptoJS不符合 你的需求,然后我建议你尝试Forge。
我建议将代码移动到使用推荐的其他Javascript库。例如伪造支持RSA签名(https://github.com/digitalbazaar/forge#rsa)
Google OAuth2服务器使用 RS256 。我提供了一个代码片段来转换密钥(我假设PEM格式),使用带有SHA256的RSA伪造和签名数据
Google OAuth 2.0授权服务器支持的唯一签名算法是使用SHA-256哈希算法的RSA。这在JWT标题的alg字段中表示为RS256。
// convert a PEM-formatted private key to a Forge private key
var privateKey = forge.pki.privateKeyFromPem(pem);
// sign data with a private key and output DigestInfo DER-encoded bytes (defaults to RSASSA PKCS#1 v1.5)
var md = forge.md.sha256.create();
md.update(byteArray, 'utf8');
var signature = privateKey.sign(md);
//convert signature to base64
var encodedSignature = Base64EncodeUrl(btoa(signature));