流程
- 客户端生成随机
code_verifier及其 SHA-256code_challenge。 - 携带
client_id、redirect_uri、scope、state与 challenge 重定向到授权端点。 - 用户认证并同意;服务器带授权码和原始 state 重定向回来。
- 客户端校验
state,在令牌端点用授权码与 verifier 交换令牌。 - 令牌端点返回访问令牌,并在允许时返回刷新令牌。
PKCE 代码
const verifier = crypto.randomBytes(32).toString('base64url');
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
const authUrl = new URL('https://auth.example.com/authorize');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', clientId);
authUrl.searchParams.set('redirect_uri', redirectUri);
authUrl.searchParams.set('scope', 'openid profile');
authUrl.searchParams.set('state', state);
authUrl.searchParams.set('code_challenge', challenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
何时使用
在浏览器、移动端和服务端渲染应用中进行委托 API 访问时使用授权码 + PKCE。与在客户端嵌入凭据相比,OAuth 把密码保留在授权服务器,并用 scope 与短期令牌限制访问;与自建令牌系统相比,它提供标准流程和可互操作库。
陷阱
缺少或不校验 state 会导致登录 CSRF。通配符重定向 URI 会把授权码发给攻击者。把令牌存在 localStorage 会暴露给 XSS;架构允许时优先使用安全的 HttpOnly Cookie。刷新令牌需要轮换与重用吊销。始终校验接受令牌的签发方、受众和签名。