通过 Node-Fetch 检索 OAuth2 令牌

Posted

技术标签:

【中文标题】通过 Node-Fetch 检索 OAuth2 令牌【英文标题】:Retrieving OAuth2 Token Via Node-Fetch 【发布时间】:2020-10-22 21:50:36 【问题描述】:

问题是我正在尝试检索 OAuth2 令牌。由于request 已被弃用,我为此使用node-fetch。虽然我可以让它与request 一起工作,但我不能与node-fetch 一起工作。

我已经阅读了很多关于这里的帖子,但似乎没有一个真正给出真正有效的一致答案。我承认我看起来还不够好。我将其包装在测试中可能也很复杂,但由于我收到的错误消息,感觉并非如此。

这是有效的代码(请注意,我必须更改详细信息以保护内部 URL):

var request = require("request");

var options = 
  method: "POST",
  url: "https://some-url/realms/my-realm/protocol/openid-connect/token",
  headers:  "Content-Type": "application/x-www-form-urlencoded" ,
  form: 
    username: "JeffUser",
    password: "jeff-password",
    grant_type: "password",
    client_id: "jeff-client",
    client_secret: "jeff-client"
  
;

request(options, function(error, response, body) 
  if (error) throw new Error(error);

  console.log(body);
)

这行得通,我得到了令牌。这是我在node-fetch(包含在测试中)中尝试的失败:

const assert = require("chai").assert;
const fetch = require("node-fetch")

describe("Test API", function() 
  let api_token = "";

  it("gets a token", async function() 
    api_token = await fetch("https://some-url/realms/my-realm/protocol/openid-connect/token", 
      method: "post",
      headers: 
        "Content-Type": "application/x-www-form-urlencoded",
      ,
      form: 
        username: "JeffUser",
        password: "jeff-password",
        grant_type: "password",
        client_id: "jeff-client",
        client_secret: "jeff-client"
      
    ).then (response => 
      return response.json();
    );

    console.log(token);
  );
);

这里发生的是我从该测试中得到以下输出:


  error: 'invalid_request',
  error_description: 'Missing form parameter: grant_type'

我已尝试按照某些搜索的建议将 form 更改为 body,但这似乎没有任何效果。我尝试用 JSON.stringify() 包装 form: 数据,正如其他一些搜索所建议的那样,但这也导致了同样的错误被报告。

【问题讨论】:

需要body而不是form。而且您可能需要自己处理正确格式的数据编码,不确定是否有任何自动为您做这件事。 github.com/node-fetch/node-fetch#post-with-form-parameters - 使用URLSearchParams 之类的东西以application/x-www-form-urlencoded 要求的正确格式提供您的数据。 @CBroe:谢谢。但是不清楚为什么request 代码有效,我不使用“body”。此外,没有其他逻辑(我知道)专门针对编码做任何事情。基本上我正在尝试将request 中的工作内容移植到node-fetch。我会试试URLSearchParams 的事情。 就是这样! URLSearchParams 是我需要的。谢谢! 【参考方案1】:

这要感谢@CBroe,他在 cmets 中为我提供了答案。我会将解决方案放在这里,以供遇到此问题的其他人使用。这是我必须做的:

const assert = require("chai").assert;
const fetch = require("node-fetch")

const params = new URLSearchParams();

params.append("grant_type", "password");
params.append("username", "JeffUser");
params.append("password", "jeff-password");
params.append("client_id", "jeff-client");
params.append("client_secret", "jeff-client");


describe("Test API", function() 
  let api_token = "";

  it("gets a token", async function() 
    api_token = await fetch("https://some-url/realms/my-realm/protocol/openid-connect/token", 
      method: "post",
      headers: 
        "Content-Type": "application/x-www-form-urlencoded",
      ,
      body: params
    ).then (response => 
      return response.json();
    );

    console.log(token);
  );
);

我确保使用body 而不是form。我还使用URLSearchParams 创建了一系列参数,并将其传递给body 参数。这就是诀窍!我现在得到了授权令牌。

【讨论】:

【参考方案2】:
const buffer = require("buffer")
const fetch = require("node-fetch")

let url = 'www.exampl.com/token';
let client_id = '123';
let client_secret = '323';
let username = 'test';
let password = 'test';

let basicAuth = buffer.from(`$client_id:$client_secret`).toString("base64");

const response = await fetch(url, 
 method:"POST",
 headers: 
    "Content-Type": "application/x-www-form-urlencoded",
    Accept: "application/json; charset=UTF-8", 
     Authorization: `Basic $basicAuth`, 
    ,
  body:`grant_type=password&username=$username&password=$password&scope=xfds`,
);

let token = await response.json();

console.log(token)

【讨论】:

以上是关于通过 Node-Fetch 检索 OAuth2 令牌的主要内容,如果未能解决你的问题,请参考以下文章

从 node.js 中的 API 数据中提取值

如何使用 node-fetch 通过 discord webhook 发送图像?

错误 redirect_uri:“不是格式正确的 URL。”在不和谐的 OAuth2 中

无法检索 oauth2 的访问令牌

OAuth2 - 检索令牌时 OPTIONS 请求的状态 401

Spring oauth2,使用访问令牌检索用户数据?