[英]How to build request for oAuth2 using nodejs ?"
我正在尝试使用nodejs实现oAuth2.0,我想到的方法是调用第一个令牌端点并获取令牌,然后使用令牌调用实际端点来获取数据。 我从后端获取未定义的令牌。
我需要以下场景的帮助,什么是为后端获取 oAuth2 令牌的最佳方法。
main.js
function getAllEODList() {
const options = {
"tokenHost": "https://test/oauth2/token",
"addAuthTokenTo": "header",
"body": {
"scope": "APPPII APPPHI",
"grant_type": "client_credentials"
},
"credentials": {
"sdk_voyage": {
"clientId": "xyz",
"clientSecret": "zbc"
}
},
"authorizationMethod": "header/form"
}
const promise = do_something(options)
.then(function(my_data){
const options2 = {
url: 'https://apiwebsite.com',
headers: {'authorization' : 'Bearer ' + my_data, 'Content-Type' : 'application/json'},
port: '443',
path: '/users',
method: 'GET'
}
do_something_else(options2)
.then(function(my_other_data){
//do stuff with my_other_data
}
}
}
我对你如何表达你的问题和你的代码没有意义感到有点困惑,但我得到的要点是你想从后端获取一个令牌并且你正在尝试实现 OAuth 2.0,所以我会尽我所能在 Node.js 的背景下回答这个问题。 顺便说一句,当您说:“调用第一个令牌端点并获取令牌,然后使用令牌调用实际端点以获取数据。”,这不符合 OAuth 2.0 指定的推荐协议,并且在事实不安全。 我将首先解释你应该做什么,然后是如何实现它。
我将从实现RFC6749中定义的授权代码授权类型的角度回答这个问题,这是推荐使用的(使用 RFC6736 定义的PKCE ,但我将在此答案中省略 PKCE,因为它'只会让事情复杂化。不过,请随意阅读链接的 RFC。
RFC6749 定义了在授权码授权类型中使用的两个授权服务器端点:授权端点和令牌端点。 这在 RFC6749 的第 3 节中有描述,但我将对其进行总结:
客户端使用 Authorization 端点来获取授权,在本例中为code 。 这段代码是你需要生成服务器端并以某种方式存储的东西。 代码应该具有高熵,并且应该按照规范的定义在不超过 10 分钟的时间内有效。 您可以通过使用crypto
模块生成一些随机字节并以某种方式将其缓存在您的后端 10 分钟来完成此操作。
令牌端点是客户端用来获取令牌的端点,必须提供有效代码才能获取令牌。
现在让我们查看整个流程:
客户端单击客户端前端的登录按钮。 客户端被重定向到授权服务器。 uri 非常重要,应该如下所示:
http://auth.example.com/authorize?grant_type=code&redirect_uri=http://example.com/callback&scope=openid scope1 scope2&client_id=example-client-id&state=some-opaque-value。
这个 url 不是 URL 编码的,但你明白我的意思(空格将替换为正确的 url 安全字符)。 URL 包含五个内容:
根据RFC6749 第 4.1.1 节,授权服务器应验证此 URL 并确保其具有必要的查询参数,如果不是,则不应服务任何请求
如果 URL 有效,则 Authz 应显示登录或注册页面,并验证最终用户的凭据。 如果它们不正确,Authz 不应将它们重定向到 redirect_uri,而是显示某种错误 flash 消息。 但是,如果客户端验证成功,Authz 应该生成一个代码,即在您的情况下,您可以使用 Node.js crypto
模块生成一个随机字符串。 这应该与客户端先前提供的 state 一起附加到重定向 uri < - 这很重要。 即:您的 Authz 应该将最终用户重定向回如下所示的内容:
http://example.com/callback?code=your-generated-code&state=the-state-that-was-presented
一旦发生这种情况,客户端应验证 url 中的state参数是否与其最初创建的参数相同。 如果它无效,则不应使用该代码 --> 有人在攻击您或您有错误。 如果 state 参数正确,那么您在该重定向 url 中收到的代码现在应该用于在我之前解释的令牌端点获取令牌。
您在授权服务器上对令牌端点的请求可能如下所示:
您的 Authz 现在应该验证
如果一切顺利,Authz 应该创建并生成一个令牌,通常是 JSON Web 令牌 (JWT),其中包含以下声明,如RFC9068中所述。 为了节省您一些时间,这些声明应该是:
现在您的客户拥有一个令牌,他们应该能够使用它来针对您的 api 进行身份验证。
好的,现在我们已经看到了流程,这里有几个伪代码模板,您可以尝试实现它们,但是有很多因素可能会影响到这一点,例如,您的客户是公开的还是机密的(公开客户不' 除非它们被轮换并使用 PKCE 否则不会获得刷新令牌 --> 请参阅Auth0: Authorization Code Flow with PKCE
您的 Authz 可能有一个如下所示的文件:
// forgive me if my node.js isn't perfect, it's been a while since I've
// written it but you get the gist:
import { Router } from 'express'
const router = Router();
//authorization endpoint
router.route('/authorize').get(async(req,res,next)=> {
if(!validateRequestQuery(req.query)) return res.status(401).json({valid-oauth-error-msg-here});
const state = req.query.state;
const code: string = generateAuthorizationCode();
const cacheSuccess = await cacheCodeForTenMinutes();
if(!cacheSuccess) return res.status(500).json('valid-oauth-error-here');
const callbackUri = `http://example.com/callback?code=${code}&state=${state}`;
res.redirect(callbackUri);
}
)
//once the above function is called, the client needs to validate the state //it sends back!
//token endpoint
router.route('/token').get(async(req, res, next){
if(!validateTokenRequestQuery()) return a valid oauth error
const code = req.query.code
const isCodeValid = await checkCache(code);
if(!isCodeValid) return a valid oauth error
const accessToken = new Token(); // <--create a valid Access Token here
const refreshToken = new Token(accessToken); // if your client is confidential or you are using refresh token rotation and PKCE!
const idToken = new IdToken() // <-- if the openid scope is included
return res.status(200).json('accesstoken, idtoken');
// NEVER SEND REFRESH TOKEN TO FRONTEND. it is highly insecure. store it
// server side instead.
});
如果您有任何问题,请随时回复。 这是一个非常复杂的话题,我所说的某些内容可能过于模糊,所以请让我澄清一下。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.