> ## Documentation Index
> Fetch the complete documentation index at: https://stytch.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Adding PKCE to an OAuth flow

> Enable PKCE in OAuth flows for stronger protection on web and native redirects.

[Proof Key for Code Exchange (PKCE)](https://datatracker.ietf.org/doc/html/rfc7636) is a specification that builds on OAuth 2.0 to create a more secure login flow.

In the original OAuth authorization code flow, an IdP issues a one-time use code to the app, which is exchanged along with a `client_id` and `client_secret` for an auth token. For certain types of apps (i.e. SPAs, mobile apps, or native apps) there was no mechanism to hide the `client_secret`, which must be included in the app's source code and reused on every request. This meant that an attacker would be able to impersonate a user if the attacker gained access to the one-time use code. Codes in a URL can be leaked in many different ways - either through improper logging, HTTP Referrer headers, or even through another exploit like XSS.

PKCE introduces a one-time secret for each authorization flow. This secret, called a `code_verifier`, is generated and stored by the app on the user's device. Before the user is redirected to the IdP, the verifier is hashed to produce a `code_challenge`. This challenge is passed as a query parameter during the authentication flow, e.g. `/oauth/authenticate?code_challenge=E9Mel....`

After the IdP has validated the user's credentials, the user is redirected back to the app with a secure code. Now, the app must submit the code along with the original `code_verifier`. The IdP hashes the submitted `code_verifier` and validates that it matches the `code_challenge` passed as a query parameter earlier. This check ensures that the token has not been leaked, and that it is being handled by the same user that was seen at the start of the flow.

This guide will show you how to add PKCE support to your Stytch OAuth integration for added security. A PKCE integration is required for applications that use native callback URLs, for example `appname://some/callback` on mobile. Stytch's support for PKCE differs slightly from the original specification - for example we do not permit plain verifiers to be used - but the original idea of strengthening app security with a unique secret on every request remains the same.

If you get stuck while working through this guide, feel free to ask questions via [support@stytch.com](mailto:support@stytch.com) or in our [Slack community](https://join.slack.com/t/stytch/shared%5Finvite/zt-3aqo03e10-afWXyLzRIAlzGWJyF%5F~zHw).

<Tabs>
  <Tab title="JavaScript SDK">
    <Steps>
      <Step title="Enable PKCE for your app">
        Enable PKCE for all OAuth logins performed by the JavaScript SDK. By flipping this setting, you tell the Javascript SDK to use PKCE for all UI components and to reject any OAuth logins that do not use PKCE. Toggle the option in the [Frontend SDK page](https://stytch.com/dashboard/sdk-configuration) of the Stytch Dashboard. This makes your application resistant to attacks like [Login CSRF](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site%5FRequest%5FForgery%5FPrevention%5FCheat%5FSheet.html#login-csrf), in which an attacker can trick a victim into logging in to the wrong account.

        **Note:** The legacy oauth.\$provider.getURL() method is not compatible with PKCE. If you are using this method already in your codebase, complete the next step before enabling PKCE.
      </Step>

      <Step title="Start the OAuth flow">
        Call one of the [oauth.\$provider.start()](/api-reference/consumer/frontend-sdks/vanilla-js/methods/oauth/start) methods to start the OAuth flow. The SDK will generate a `code_verifier` and store it in local storage before redirecting the user to Stytch's OAuth start endpoint. If you use the SDK's built-in [OAuth UI](/api-reference/consumer/frontend-sdks/vanilla-js/prebuilt-ui/web-component) this step is already handled for you.

        ```js theme={null}
        function OAuthStartButton() {
          const stytch = useStytch();
          const startOAuthFlow = useCallback(() => stytch.oauth.google.start({
            login_redirect_url: 'https://example.com/callback',
            signup_redirect_url: 'https://example.com/callback'
          }), [stytch])

          return (
            <button onClick={startOAuthFlow}>
              Click here to log in with Google
            </button>
          );
        }
        ```
      </Step>

      <Step title="Authenticate the OAuth token">
        At the route that the user is redirected to after the OAuth flow, pull the token out of the URL params and call [oauth.authenticate(token)](/api-reference/consumer/frontend-sdks/vanilla-js/methods/oauth/authenticate) to exchange the token for a Stytch session. The SDK will automatically retrieve the `code_verifier` created earlier from local storage and pass it on to the Stytch servers.

        ```js theme={null}
        function OAuthCallback() {
          const stytch = useStytch();
          useEffect(() => {
            stytch.authenticateByUrl({
              session_duration_minutes: 60,
            }).then((result) => {
              if (result?.handled) {
                // TODO: Redirect to final logged-in view
              } else {
                // TODO: Handle redirect back to logged-out view
              }
            })
          }, [stytch]);

          return (
            <div>
              Authenticating....
            </div>
          );
        }
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Direct API">
    <Steps>
      <Step title="Create a proof key pair">
        Create a `code_verifier` and `code_challenge` pair. To create the `code_verifier`, generate at least 256 random bits of entropy. This can be done by having a suitable random number generator create a 32-octet sequence. To create the `code_challenge`, hash the `code_verifier` using SHA-256 and then base64url encode both to produce ASCII strings.

        ```js theme={null}
        const pkceChallenge = require("pkce-challenge");

        const { code_verifier, code_challenge } = pkceChallenge();
        console.log("code_verifier", code_verifier);
        console.log("code_challenge", code_challenge);
        ```
      </Step>

      <Step title="Associate the proof key with the user's device">
        Associate the `code_verifier` with the user's device before starting the OAuth flow. A common approach is to store it in an HTTP-only cookie. Be sure to include the `code_challenge` as a query param when you start the OAuth flow.

        ```http theme={null}
        HTTP/2 302
        content-type: application/json
        location: https://api.stytch.com/v1/public/oauth/google/start?public_token=PUBLIC_TOKEN&code_challenge=CODE_CHALLENGE
        set-cookie: code_verifier=CODE_VERIFIER; Path=/; HttpOnly; Secure; SameSite=None
        ```
      </Step>

      <Step title="Authenticate the OAuth token with Stytch">
        After the user is redirected back from Stytch with a valid token, exchange the token along with the original `code_verifier` to complete the flow and be issued a valid Stytch session. Retrieve the `code_verifier` from the cookie where it was stored in step 2, and send it to the [Authenticate OAuth token](/api-reference/consumer/api/oauth/authenticate) endpoint.

        ```js theme={null}
        const stytch = require("stytch");

        const client = new stytch.Client({
          project_id: "PROJECT_ID",
          secret: "SECRET",
          env: stytch.envs.test,
        });

        client.oauth.authenticate("OAUTH_TOKEN", {
          code_verifier,
        })
          .then((resp) => {
            console.log(resp);
          })
          .catch((err) => {
            console.log(err);
          });
        ```
      </Step>

      <Step title="You're done">
        You have all the critical components to authenticate users via OAuth with PKCE.
      </Step>
    </Steps>
  </Tab>
</Tabs>
