Nodejs发布请求以获取服务帐户的{oauth2令牌

时间:2017-09-14 14:40:12

标签: node.js google-api request google-oauth google-api-nodejs-client

我正在尝试使用nodejs为我的服务帐户获取oauth2令牌。我正在按照此处的文档进行操作:

https://developers.google.com/identity/protocols/OAuth2ServiceAccount#makingrequest

虽然没有节点示例,但我查看了HTTP / Rest文档,以便大致了解在发出令牌请求时所期望的内容。但是我得到的回应是:

无效的JWT签名。

作为计算签名时的一般概述,您将获取标头和声明的base64url编码值,使用sha256和Google开发者控制台中的私钥对其进行哈希处理,然后使用base64url对该值进行编码。

所以我的标题是:

    var header = {"alg":"RS256","typ":"JWT"}
    var encodedHeader = base64url(new Buffer(header).toString('utf8'));

上面的文档甚至列出了base64url编码后该值的含义:

    eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9

当我输出encodedHeader值时:

    eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9

哦非常好匹配。所以其他值不应该有64burl编码问题。接下来是索赔:

    var claim ={"aud":"https://www.googleapis.com/oauth2/v4/token","scope":"https://www.googleapis.com/auth/gmail.send","iss":"*****censoredvalue*****gserviceaccount.com","exp":1505399833,"iat":1505396233}

它经历了相同的过程并被编码。(出于安全原因无法显示)。

    var encodedClaim = base64url(new Buffer(claim).toString('utf8'));

目前我正在使用第三方网站计算签名以进行测试,但输入是encodedHeader.encodedClaim +私钥(值为:----- BEGIN PRIVATE KEY ....)并使用SHA256 。然后我将获取该输出并对其进行b64url编码。

我现在有一个编码为Header.encodedClaim.encodedSignature的JWT

    var encoded_jwt = encodedHeader + '.' + encodedClaim + '.' + encodedSignature;

我将使用以下内容向令牌端点发出请求:

    // Set the headers
    var headers = {
       'HTTP-Version': 'HTTP/1.1',
       'Content-Type': 'application/x-www-form-urlencoded'
    }

    var bodyOptions = { 'grant_type': "urn:ietf:params:oauth:grant-type:jwt-bearer", assertion: encoded_jwt }

    // Configure the request
    var options = {
        url: 'https://www.googleapis.com/oauth2/v4/token',
        method: 'POST',
        headers: headers,
        form: bodyOptions,
        json: true
     }

    // Start the request
   request(options, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            // Print out the response body
            console.log(body)
        }
        else{
            context.log(error);
            context.log(response);
        }
    });

这就是我收到错误的回复,说我的签名无效。

关于为什么它是无效签名的任何想法。我也尝试了几个签名生成网站,以确保它不是一个特定的,但它总是相同的错误。

1 个答案:

答案 0 :(得分:0)

要计算JWS,您可以使用crypto module,如下所示:

const privateKey = fs.readFileSync('private.pem', 'utf-8');

const signer = crypto.createSign('sha256');
signer.update(data);
const signature = signer.sign(privateKey, 'base64');

其中dataencodedHeader + '.' + encodedClaim

google-oauth-library测试用例中获取的完整示例:

"use strict";

const crypto = require('crypto');
const fs = require('fs');

const publicKey = fs.readFileSync('public.pem', 'utf-8');
const privateKey = fs.readFileSync('private.pem', 'utf-8');

const maxLifetimeSecs = 86400;
const now = new Date().getTime() / 1000;
const expiry = now + (maxLifetimeSecs / 2);

const idToken = '{' +
    '"iss":"testissuer",' +
    '"aud":"testaudience",' +
    '"azp":"testauthorisedparty",' +
    '"email_verified":"true",' +
    '"id":"123456789",' +
    '"sub":"123456789",' +
    '"email":"test@test.com",' +
    '"iat":' + now + ',' +
    '"exp":' + expiry + '}';

const envelope = '{' +
    '"kid":"keyid",' +
    '"alg":"RS256"' +
    '}';

let data = new Buffer(envelope).toString('base64') + '.' +
    new Buffer(idToken).toString('base64');

const signer = crypto.createSign('sha256');
signer.update(data);
const signature = signer.sign(privateKey, 'base64');

data += '.' + signature;

console.log(data);