我正在尝试在scriptr.io上创建一个脚本创建 JWT/JWS发送到 google 的 token 端点,以便为我的服务帐户获取 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 将请求发送到 token 端点时,我收到以下响应
{
"error": "invalid_grant",
"error_description": "Invalid JWT Signature."
}
知道我哪里出错了吗?有人可以帮助我正确格式化 JWT 以便我可以获得 token 吗?
最佳答案
使用的函数是进行哈希计算,而不是数字签名
var signature = cryptoJs.SHA256(byteArray, secret);
不支持使用 RSA 私钥进行数字签名。看看CryptoJS主存储库中的评论
Inactivity
CryptoJS is a project that I enjoy and work on in my spare time, but unfortunately my 9-to-5 hasn't left me with as much free time as it used to. I'd still like to continue improving it in the future, but I can't say when that will be. If you find that CryptoJS doesn't meet your needs, then I'd recommend you try Forge.
我建议移动代码以使用推荐的其他 Javascript 库。例如 forge 支持 RSA 签名 ( https://github.com/digitalbazaar/forge#rsa )
<小时/>Google OAuth2 服务器使用RS256。我提供了一个片段来转换 key (我假设 PEM 格式),以使用 RSA 和 SHA256 来伪造和签名数据
The only signing algorithm supported by the Google OAuth 2.0 Authorization Server is RSA using SHA-256 hashing algorithm. This is expressed as RS256 in the alg field in the JWT header.
// 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));
关于javascript - 为 Google 服务帐户身份验证正确创建 JWT 时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42015178/