提问人:NotX 提问时间:9/1/2023 最后编辑:NotX 更新时间:9/3/2023 访问量:438
NextJS 中的授权代码流 - 如何将 PKCE code_verifier传递给授权回调?
Authorisation Code Flow in NextJS - how to pass PKCE code_verifier to the authorization callback?
问:
我已经使用 openid-client 在 NextJS 中实现了 OAuth2 授权代码流(还没有 PKCE)。现在我应该在哪里存储它以及如何将其传递给服务器端调用的回调。code_verifier
到目前为止我做了什么(草图):
// on server-side:
import { BaseClient, Issuer, custom, generators } from 'openid-client';
const issuer = await Issuer.discover('https://www.my-oidc-provider-endpoint');
const client = new issuer.Client({
client_id: 'myClientId',
client_secret: 'myClientSecret',
redirect_uri: `${process.env.NEXT_PUBLIC_APP_URL}/api/auth/callback`,
});
// This must happen on server-side b/c the library is not available in the browser:
// const code_verifier = generators.codeVerifier();
// const code_challenge = generators.codeChallenge(code_verifier);
const authorizationUrl = client.authorizationUrl({
scope: 'openid email profile rights',
// code_challenge,
// code_challenge_method: 'S256',
})
// on client-side
// the authorizationUrl was passed via getStaticProps
window.location.assign(authorizationUrl)
在我的 API 端点中,一旦用户在以下位置输入其凭据,就会调用:api/auth/callback
https://www.my-oidc-provider-endpoint.tld
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const client = await authClientProvider.getClient();
const params = client.callbackParams(req);
const tokenSet = await client.callback(`${APP_URL}/api/auth/callback`, params/* , {code_verifier}*/);
setTokenCookies(req, res, tokenSet.access_token, tokenSet.refresh_token); // implemented elsewhere
return res.redirect(APP_URL);
}
这一切正常,但不能实现 PKCE。所以我的问题是:
目前,我会将 作为 的一部分传递给客户端。这就足够了吗?但是我如何让它可用于我的回调端点,这是我所理解的纯服务器端?我是否必须使用参数并在服务器端使用 as 键缓存?code_verifier
authorizationUrl
api/auth/callback
state
code_verifier
state
我发现了一个类似的问题,但提问者似乎并不为将其存储在 cookie 中而烦恼(我必须从一开始就刮掉它,出于什么原因?如果是为了安全起见,我可以在服务器端对其进行加密),而且他们似乎并不担心将其传递给服务器端的回调处理程序。我可以直接在客户端生成我的(没有 from 的帮助),但这并没有像预期的那样打击我,我仍然无法将其传递给 api 回调。authorization_url
code_verifier
generators
openid-client
(旁注:我不想使用 NextAuth。实际上,我们是从那里来的,但它造成了太多的麻烦。
答:
如果你可以把它存储在服务器端(加密它不是一个坏主意),那么这通常是更好的途径。麻烦出在重定向上,并寻找哪个code_verifier进行代币交换。您可以创建类似会话 ID 的内容,并将其用作查找的键:https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#session-id-properties
另一种方法是加密并在 cookie 中发送它,确保对 cookie 采取适当的预防措施: https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html#server-security cookie 应该往返于您可以解密并将其用于令牌交换的地方。这里的风险是有人可以访问和解密(如果未充分加密)您的code_verifier,因为它是通过网络调用传递的。
编辑 2023/9/2
添加一些额外的细节(最初是作为注释添加的,但它变得很长,并认为它可能对其他人有所帮助):
使用 cookie 不需要额外的往返行程。要小心,因为客户端的使用方式略有不同。
方案中的“OAuth 客户端”是指服务器RFC6749。
client.authorizationUrl()
在 open-id 中使用的只是一个占位符函数调用。它的实现应该告诉浏览器/用户代理重定向到端点的 authz 服务器。这是 authz 请求。PKCE 要求在此请求中包含 and。/authorize
code_challenge
code_challenge_method
用户进行身份验证,然后将用户代理发送到redirect_uri。
在redirect_uri,您的服务器通过浏览器获取,因为用户需要能够返回到您的应用程序。code
然后,您的服务器或同一关系图中的客户端直接向 authz 服务器的端点发出请求,而不是通过浏览器发出请求。按照该图中的 (d) 操作。该请求包括 和 。/token
code
code_verifier
Cookie 在您的服务器上创建并发送到浏览器并存储它。当用户通过浏览器发送回redirect_uri时,对服务器的调用包括 cookie。
或者,换一种说法:
- 服务器创建一个code_verifier,加密并存储在cookie中
- 从服务器发送到浏览器的 cookie 和 authz url
- 浏览器存储 Cookie
- 浏览器重定向到终结点
/authorize
- ...
- 浏览器重定向到
redirect_uri
- 浏览器向服务器发送 cookie
code
- 服务器解密 cookie
- 服务器发送 并直接发送到 。
code_verifier
code
/token
所以,这是同样的往返,但现在只是用一块饼干。
编辑 #2 2023/9/2
更多信息可能会有所帮助:
oidc 提供程序在对用户进行身份验证后将浏览器重定向到 。“授权服务器将用户代理重定向到客户端的重定向端点”。当浏览器到达 时,它应该使用 cookie 向您的 API 发出请求。redirect_uri
redirect_uri
+----------+ | Resource | | Owner | | | +----------+ ^ | (B) +----|-----+ Client Identifier +---------------+ | -+----(A)-- & Redirection URI ---->| | | User- | | Authorization | | Agent -+----(B)-- User authenticates --->| Server | | | | | | -+----(C)-- Authorization Code ---<| | +-|----|---+ +---------------+ | | ^ v (A) (C) | | | | | | ^ v | | +---------+ | | | |>---(D)-- Authorization Code ---------' | | Client | & Redirection URI | | | | | |<---(E)----- Access Token -------------------' +---------+ (w/ Optional Refresh Token)
(C) 假设资源所有者授予访问权限,则授权 服务器使用 之前提供的重定向 URI(在请求中或期间) 客户注册)。重定向 URI 包括 客户端提供的授权代码和任何本地状态 早些时候。
请注意,(C) 实际上有 2 行。一个从 到 (浏览器),然后另一个从 到 .这是在用户向授权服务器(或 OAuth/OIDC 提供商)进行身份验证后重定向回您的应用。授权代码包含在此行中。Authorization Server
User-Agent
User-Agent
Client
第二行 (C) 是图中 to 的那一行,是浏览器将带有加密的 cookie 与 .User-Agent
Client
code_verifier
code
+----|-----+ | | | User- | | Agent | | | | | +------|---+ | authorization code (C) and | (code_verifier) cookie v +---------+ | | | Client | | | | | +---------+
评论
client.authorizationUrl(...)
code_verifier
code_verifier
/token
client.authorizationUrl()
code_challenge
code_challenge_method
redirect_uri
redirect_uri
redirect_uri
redirect_uri
评论