OAuth交换提供invalid_grant和Bad请求

时间:2018-06-05 21:41:29

标签: oauth-2.0 google-oauth google-api-nodejs-client

尝试将OAuth用于本地Node.js脚本时,我遇到了一些奇怪的行为。我现在的目标是在用户授权我的项目时从用户处获取刷新令牌。

我尽可能多地依赖Google的图书馆,但我仍然遇到问题。

当我尝试运行设置时,我正确地获取了OAuth页面并创建了一个授权令牌:

const { google } = require('googleapis');

const oauth2Client = new google.auth.OAuth2(
    clientId,
    clientSecret,
    'urn:ietf:wg:oauth:2.0:oob'
);
const scopes = [
    'https://www.googleapis.com/auth/calendar'
];

我在控制台中为用户提供了URL:

const url = oauth2Client.generateAuthUrl({
    // 'online' (default) or 'offline' (gets refresh_token)
    access_type: 'offline',

    // If you only need one scope you can pass it as a string
    scope: scopes
});

console.log(url);

然后我打开URL并生成令牌。我提示用户提供此值:

stdio.question('Authorization code', (err, code) => {
    // Use this code to obtain a refresh token
    console.log("CODE", code);
    oauth2Client.getToken(code, (err, tokens) => {
        console.log(err, tokens);
    });
});

当我到达这一点时,我遇到了一个错误:

error: 'invalid_grant', error_description: 'Bad Request'

目前尚不清楚这是哪里出错。

如果我使用相同的身份验证令牌并使用cURL,它实际上按预期工作,所以就我所知,这不是配置错误。

curl -s -X POST -d 'code='$CODE'&client_id='$CLIENT_ID'&client_secret='$CLIENT_SECRET'&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code' https://www.googleapis.com/oauth2/v4/token

{
  "access_token": "ACCESS",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "REFRESH"
}

更有趣的是,如果我通过流程并获得错误,尝试运行cURL命令将返回一个错误,表明请求已在某种程度上被接受:

{
  "error": "invalid_grant",
  "error_description": "Code was already redeemed."
}

这个OAuth库中发生了什么导致cURL没有发生无效授权问题,我该怎么做才能纠正Node.js代码?

1 个答案:

答案 0 :(得分:0)

事实证明,stdio库的一个问题是,在您收到回调之前,您输入的所有文字最终都是converted to lowercase。这导致invalid_grant错误。

更好的方法是使用Node.js中的内置readline模块

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.question('Authorization code: ', (code) => {
  // Use this code to obtain a refresh token
  console.log("CODE", code);
  oauth2Client.getToken(code, (err, tokens) => {
    console.log(err, tokens);
    rl.close();
  });
});