Search code examples
javascriptoauth-2.0oauthauth0okta

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


Following Okta's auth code flow, they say I need to create a PKCE code which contains a code verifier and challenger.

It is not clear how to create the values like their example:

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

I know I can send the code challenge in the auth URL like so:

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

But it is not clear what I do with the verifier. It says:

Your app saves the code_verifier for later

Where do I save it the verifier and how do I create these values?

EDIT: Showing code where I set the code_verifier in localStorage

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>
  );
};

Solution

  • Turns out I was trying to generate the auth string manually. Doing this skips the step that creates the code_verifier (as @philipp-grigoryev pointed out).

    I should have been using the Okta sdk to redirect the user which handles the saving the code_verifier in local storage and when the user is redirected back, it extracts the value from local storage again.

    This is how I used the SDK to redirect the user to 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
      });
    };