如何为授权代码流创建 PKCE 代码和验证程序?

How to create PKCE code and verifier for auth code flow?

遵循 Okta 的授权代码流程,they say I need to create a PKCE code 其中包含代码验证器和挑战器。

不清楚如何像他们的示例那样创建值:

{
  "code_verifier":"M25iVXpKU3puUjFaYWg3T1NDTDQtcW1ROUY5YXlwalNoc0hhakxifmZHag",
  "code_challenge":"qjrzSW9gMiUgpUvqgEPE4_-8swvyCtfOVvg55o5S_es"
}

我知道我可以像这样在 auth URL 中发送代码质询:

https://${ourOktaDomain}/oauth2/v1/authorize?idp=${idp}&client_id=${clientId}&response_type=code&response_mode=query&scope=openid%20email&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Flogin%2Fcallback&state=${randomString}&code_challenge=${codeChallenge}&code_challenge_method=S256

但不清楚我用验证器做了什么。它说:

Your app saves the code_verifier for later

在哪里保存验证程序以及如何创建这些值?

编辑:显示我在 localStorage

中设置 code_verifier 的代码
const Login = () => {

  const codeVerifier = useMemo(async () => {
    const s256 = await sha256(codeChallenge)
    const verifier = btoa(s256);

    window.localStorage.setItem(state, verifier);
    
    return verifier;
  }, [])

  if (!codeVerifier) {
    return <div>Loading...</div>;
  }

  const queryParams = encode({
    client_id: CLIENT_ID,
    redirect_uri: encodeURI(REDIRECT_URI),
    response_type: 'code',
    response_mode: 'query',
    state,
    nonce,
    code_challenge: codeChallenge,
    code_challenge_method: 'S256',
    scope: 'openid email',
    idp: OKTA_IDP
  });

  const socialLoginURI = `${OKTA_AUTH_URI}?${queryParams}`;

  return (
    <Button 
      component="a"
      href={socialLoginURI}
      aria-label="Login Button"
    >
      Facebook Login
    </Button>
  );
};

verifier 在稍后阶段交换令牌的代码期间发送。你如何存储它,这取决于你。 https://datatracker.ietf.org/doc/html/rfc7636#section-4.2

中描述了验证者产生挑战的机制

原来我是想手动生成授权字符串。这样做会跳过创建 code_verifier 的步骤(正如@philipp-grigoryev 指出的那样)。

我应该一直使用 Okta sdk 来重定向处理在本地存储中保存 code_verifier 的用户,当用户被重定向回来时,它会再次从本地存储中提取值。

这就是我使用 SDK 将用户重定向到 auth 的方式

const onSocialLogin = () => {
  oktaAuth.signInWithRedirect({ 
    originalUri: '/welcome',
    clientId: CLIENT_ID,
    redirectUri: encodeURI(REDIRECT_URI),
    responseType: 'code',
    responseMode: 'query',
    state,
    nonce,
    codeChallenge,
    codeChallengeMethod: 'S256',
    scopes: ['openid', 'email'],
    idp: FACEBOOK_APP_ID
  });
};