> ## 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 OAuth to a custom auth flow

> Integrate OAuth with Stytch's headless or backend SDKs for complete control over your authentication flow.

export const ist = "A session token designed to preserve state when the user has completed an initial authentication step, but has not fully authenticated into an Organization.";

export const organization = "Represents an instance or tenant in your application, typically mapping to each of your top-level customers.";

export const discovery = "Centralized login flow that allows users to view all Organizations they have access to, including pending invites and Organizations they are allowed to automatically join based on their verified email domain.";

<Note>
  Before you begin, make sure you've completed the [OAuth configuration steps](/multi-tenant-auth/authentication/oauth/configuring-oauth-for-your-project).
</Note>

## Overview

<Tabs>
  <Tab title="Headless frontend SDK">
    This guide walks through integrating OAuth using Stytch's headless frontend SDKs. This approach gives you complete control over your UI while handling authentication logic on the frontend.

    Both <Tooltip tip={discovery}>Discovery</Tooltip> and Organization-specific authentication flows are supported.

    <Tabs>
      <Tab title="Discovery authentication">
        The Discovery flow is designed for situations where end users are signing up or logging in from a central landing page, and have not specified which <Tooltip tip={organization}>Organization</Tooltip> they are trying to access.

        ### Prerequisites

        1. Complete the steps in the [OAuth configuration guide](/multi-tenant-auth/authentication/oauth/configuring-oauth-for-your-project)
        2. Enable the Frontend SDKs in [your Stytch Dashboard](https://stytch.com/dashboard/sdk-configuration)
        3. Enable Create Organizations under "Enabled Methods"

        ### Implementation

        <Steps>
          <Step title="Start the OAuth Discovery flow">
            In your application's UI, use `oauth.discovery.$provider.start()` to allow users to begin the OAuth Discovery flow.

            <CodeGroup>
              ```jsx React icon="react" theme={null}
              import { useStytchB2BClient } from '@stytch/react/b2b';

              export const Login = () => {
                const stytchClient = useStytchB2BClient();

                const startOAuth = () =>
                  stytchClient.oauth.google.discovery.start();

                return <button onClick={startOAuth}>Log in with Google</button>;
              };
              ```

              ```html Vanilla JS icon="square-js" theme={null}
              <script>
                import { StytchB2BClient } from '@stytch/vanilla-js/b2b';
                const stytch = new StytchB2BClient('STYTCH_PUBLIC_TOKEN');

                document.getElementById('login-with-oauth').onclick = () =>
                  stytch.oauth.google.discovery.start();
              </script>

              <button id="login-with-oauth">Login with Google</button>
              ```
            </CodeGroup>
          </Step>

          <Step title="Handle the OAuth callback">
            Stytch will send a callback to the Discovery Redirect URL you specified in the [Stytch Dashboard](https://stytch.com/dashboard/redirect-urls). Exchange the token for a list of Discovered Organizations that the user can choose to log into.

            <CodeGroup>
              ```jsx React icon="react" theme={null}
              import { useEffect } from 'react';
              import { useStytchB2BClient, useStytchMemberSession } from '@stytch/react/b2b';
              import { useNavigate } from 'react-router';

              export const Authenticate = () => {
                const stytchClient = useStytchB2BClient();
                const { session } = useStytchMemberSession();
                const navigate = useNavigate();

                useEffect(() => {
                  if (session) {
                    navigate('/profile');
                  } else {
                    stytchClient.authenticateByUrl({
                      session_duration_minutes: 60,
                    });
                  }
                }, [stytchClient, session, navigate]);

                return <div>Loading...</div>;
              };
              ```

              ```html Vanilla JS icon="square-js" theme={null}
              <script>
                import { StytchB2BClient } from '@stytch/vanilla-js/b2b';
                const stytch = new StytchB2BClient('STYTCH_PUBLIC_TOKEN');

                await stytch.authenticateByUrl({
                  session_duration_minutes: 60,
                });
              </script>
              ```
            </CodeGroup>

            <Info>
              An <Tooltip tip={ist}>intermediate\_session\_token</Tooltip> will be returned. The headless SDK will automatically set this in cookies and include it in follow-up calls.
            </Info>
          </Step>

          <Step title="Handle organization selection">
            When the end user selects an Organization to log into, call the exchange intermediate session method with the selected Organization ID.

            <CodeGroup>
              ```jsx React icon="react" theme={null}
              import { useEffect } from 'react';
              import { useStytchB2BClient } from '@stytch/react/b2b';

              export const ExchangeIntermediateSession = () => {
                const stytch = useStytchB2BClient();

                useEffect(() => {
                  stytch.discovery.intermediateSessions.exchange({
                    organization_id: 'organization-test-07971b06-ac8b-4cdb-9c15-63b17e653931'
                  });
                });

                return <div>Log In</div>;
              };
              ```

              ```javascript Vanilla JS icon="square-js" theme={null}
              import { StytchB2BClient } from '@stytch/vanilla-js/b2b';
              const stytch = new StytchB2BClient('STYTCH_PUBLIC_TOKEN');

              const exchangeIntermediateSession = () => {
                stytch.discovery.intermediateSessions.exchange({
                  organization_id: 'organization-test-07971b06-ac8b-4cdb-9c15-63b17e653931'
                });
              };
              ```
            </CodeGroup>
          </Step>

          <Step title="(Optional) Support organization creation">
            Allow users to create a new Organization instead of logging into an existing one.

            <CodeGroup>
              ```jsx React icon="react" theme={null}
              import { useEffect } from 'react';
              import { useStytchB2BClient } from '@stytch/react/b2b';

              export const CreateOrganization = () => {
                const stytch = useStytchB2BClient();

                useEffect(() => {
                  stytch.discovery.organizations.create();
                });

                return <div>Create Organization</div>;
              };
              ```

              ```javascript Vanilla JS icon="square-js" theme={null}
              import { StytchB2BClient } from '@stytch/vanilla-js/b2b';
              const stytch = new StytchB2BClient('STYTCH_PUBLIC_TOKEN');

              const createOrganization = () => {
                stytch.discovery.organizations.create();
              };
              ```
            </CodeGroup>

            <Tip>
              You can optionally prompt the user for the name and slug of their new Organization. If not provided, Stytch will auto-generate them based on the end user's email address.
            </Tip>
          </Step>
        </Steps>
      </Tab>

      <Tab title="Organization-specific authentication">
        If end users login via a page that indicates which Organization they're trying to access (e.g., `<org-slug>.your-app.com` or `your-app.com/team/<org-slug>`), you can offer Organization-specific authentication.

        ### Prerequisites

        1. Complete the steps in the [OAuth configuration guide](/multi-tenant-auth/authentication/oauth/configuring-oauth-for-your-project)
        2. Enable the Frontend SDKs in [your Stytch Dashboard](https://stytch.com/dashboard/sdk-configuration)

        ### Implementation

        <Steps>
          <Step title="Start the OAuth flow">
            Use the `oauth.$provider.start()` method to initiate the OAuth flow for a specific Organization.

            <CodeGroup>
              ```jsx React icon="react" theme={null}
              import { useStytchB2BClient } from '@stytch/react/b2b';

              export const Login = () => {
                const stytchClient = useStytchB2BClient();

                const startOAuth = () =>
                  stytchClient.oauth.google.start({
                    slug: 'your-org-slug'
                  });

                return <button onClick={startOAuth}>Log in with Google</button>;
              };
              ```

              ```html Vanilla JS icon="square-js" theme={null}
              <script>
                import { StytchB2BClient } from '@stytch/vanilla-js/b2b';
                const stytch = new StytchB2BClient('STYTCH_PUBLIC_TOKEN');

                document.getElementById('login-with-oauth').onclick = () =>
                  stytch.oauth.google.start({
                    slug: 'your-org-slug'
                  });
              </script>

              <button id="login-with-oauth">Login with Google</button>
              ```
            </CodeGroup>
          </Step>

          <Step title="Handle the OAuth callback">
            Stytch will redirect the user to the Login or Signup Redirect URL. Extract the token from the URL and call the authentication method to finish the login process.

            <CodeGroup>
              ```jsx React icon="react" theme={null}
              import { useEffect } from 'react';
              import { useStytchB2BClient, useStytchMemberSession } from '@stytch/react/b2b';
              import { useNavigate } from 'react-router';

              export const Authenticate = () => {
                const stytchClient = useStytchB2BClient();
                const { session } = useStytchMemberSession();
                const navigate = useNavigate();

                useEffect(() => {
                  if (session) {
                    navigate('/profile');
                  } else {
                    stytchClient.authenticateByUrl({
                      session_duration_minutes: 60,
                    });
                  }
                }, [stytchClient, session]);

                return <div>Loading</div>;
              };
              ```

              ```html Vanilla JS icon="square-js" theme={null}
              <script>
                import { StytchB2BClient } from '@stytch/vanilla-js/b2b';
                const stytch = new StytchB2BClient('STYTCH_PUBLIC_TOKEN');

                await stytch.authenticateByUrl({
                  session_duration_minutes: 60,
                });
              </script>
              ```
            </CodeGroup>
          </Step>
        </Steps>
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Backend SDK">
    This guide walks through integrating OAuth using Stytch's backend SDKs. This approach handles all authentication logic on your backend, giving you complete control over the user experience.

    Both <Tooltip tip={discovery}>Discovery</Tooltip> and Organization-specific authentication flows are supported.

    <Tabs>
      <Tab title="Discovery authentication">
        The Discovery flow is designed for situations where end users are signing up or logging in from a central landing page, and have not specified which <Tooltip tip={organization}>Organization</Tooltip> they are trying to access.

        ### Prerequisites

        Complete the steps in the [OAuth configuration guide](/multi-tenant-auth/authentication/oauth/configuring-oauth-for-your-project)

        ### Implementation

        <Steps>
          <Step title="Configure the callback route">
            Stytch will make a callback to the Discovery Redirect URL that you specified in the [Stytch Dashboard](https://stytch.com/dashboard/redirect-urls). Handle the callback and authenticate the token.

            ```python Python icon="python" theme={null}
            @app.route("/discovery", methods=["GET"])
            def discovery() -> str:
                token_type = request.args["stytch_token_type"]
                token = request.args["token"]
                if token_type != "discovery_oauth":
                    return "Unsupported auth method"

                resp = stytch_client.oauth.discovery.authenticate(discovery_oauth_token=token)
                if resp.status_code != 200:
                    return "Authentication error"

                # Store IST as cookie for use in subsequent request to exchange
                session['ist'] = resp.intermediate_session_token

                orgs = []
                for discovered in resp.discovered_organizations:
                    org = {
                        "organization_id": discovered.organization.organization_id,
                        "organization_name": discovered.organization.organization_name,
                    }
                    orgs.append(org)

                return render_template(
                    'discoveredOrgs.html',
                    discovered_organizations=orgs,
                    email_address=resp.email_address
                )
            ```
          </Step>

          <Step title="Create organization selection UI">
            On your frontend, render the list of discovered organizations and allow users to select one.  Call the endpoint we'll setup in the next step with the selected `organization_id`.
          </Step>

          <Step title="Handle organization selection">
            Create routes to handle logging into an existing Organization or creating a new Organization.

            ```python theme={null}
            @app.route("/login/<string:organization_id>", methods=["GET"])
            def login_to_org(organization_id):
                ist = session.get('ist')
                if not ist:
                    return "No IST found"

                resp = stytch_client.discovery.intermediate_sessions.exchange(
                    intermediate_session_token=ist,
                    organization_id=organization_id
                )
                if resp.status_code != 200:
                    return "Error logging into org"

                # Clear IST and set stytch session
                session.pop('ist', None)
                session['stytch_session'] = resp.session_token
                return member.json()

            @app.route("/create_org", methods=["GET"])
            def create_org() -> str:
                ist = session.get('ist')
                if not ist:
                    return "No IST found"

                # Created org name and slug will be based on user's email
                # Can also prompt end user to provide these
                resp = stytch_client.discovery.organizations.create(
                    intermediate_session_token=ist,
                    organization_slug='',
                    organization_name=''
                )
                if resp.status_code != 200:
                    return "Error creating org"

                # Clear IST and set stytch session
                session.pop('ist', None)
                session['stytch_session'] = resp.session_token
                return member.json()
            ```
          </Step>

          <Step title="Initiate OAuth flow">
            Test the OAuth flow by navigating to the following URL in your browser. Replace `{provider}` with "google" or "microsoft" and `{public_token}` with your Public Token from the [Stytch Dashboard](https://stytch.com/dashboard).

            ```bash theme={null}
            https://test.stytch.com/v1/public/oauth/{provider}/discovery/start?public_token={public_token}
            ```

            This will automatically redirect your browser to the OAuth provider to start the flow.
          </Step>

          <Step title="(Optional) Build login UI">
            On your frontend, give users the option to start an OAuth flow with a specific provider.  For example, if you want to support Google and Microsoft OAuth:

            * Add a "Login with Google" button that links to `${apiBase}/v1/public/oauth/google/discovery/start?public_token=${public_token}`
            * Add a "Login with Microsoft" button that links to `${apiBase}/v1/public/oauth/microsoft/discovery/start?public_token=${public_token}`
          </Step>
        </Steps>
      </Tab>

      <Tab title="Organization-specific authentication">
        If end users login via a page that indicates which Organization they're trying to access (e.g., `<org-slug>.your-app.com` or `your-app.com/team/<org-slug>`), you can offer Organization-specific authentication.

        ### Prerequisites

        Complete the steps in the [OAuth configuration guide](/multi-tenant-auth/authentication/oauth/configuring-oauth-for-your-project), including creating an Organization.

        ### Implementation

        <Steps>
          <Step title="Configure the callback route">
            Stytch will make a callback to the Login or Signup Redirect URL. Handle the callback and authenticate the token.

            ```python Python icon="python" theme={null}
            @app.route("/authenticate", methods=["GET"])
            def authenticate() -> str:
                token_type = request.args["stytch_token_type"]
                if token_type == "oauth":
                    resp = stytch_client.oauth.authenticate(oauth_token=request.args["token"])
                    if resp.status_code != 200:
                        return "something went wrong authenticating token"
                else:
                    return "unsupported authentication method"

                # Member is successfully logged in
                member = resp.member
                session["stytch_session"] = resp.session_jwt
                return member.json()
            ```
          </Step>

          <Step title="Initiate OAuth flow">
            Test the OAuth flow by navigating to the following URL. Replace `{provider}` with "google" or "microsoft", and use your Public Token and Organization slug.

            ```bash theme={null}
            https://test.stytch.com/v1/public/oauth/{provider}/start?slug={organization_slug}&public_token={public_token}
            ```

            This will automatically redirect your browser to the specified OAuth provider to start the flow.
          </Step>

          <Step title="(Optional) Build organization login page">
            Create a UI that allows end users to identify the Organization they wish to log into and surface all allowed authentication methods.

            ```python theme={null}
            @app.route("/org/<string:slug>", methods=["GET"])
            def org_index(slug: str):
                # Check for active member session, if present show logged in view
                # Otherwise show login screen

                resp = stytch_client.organizations.search(query=SearchQuery(operator="AND", operands=[{
                    "filter_name": "organization_slugs",
                    "filter_value": [slug]
                }]))
                if resp.status_code != 200 or len(resp.organizations) == 0:
                    return "Error fetching org"

                organization = resp.organizations[0]
                google_allowed = (
                    organization.auth_methods == "ALL_ALLOWED" or
                    "google_oauth" in organization.allowed_auth_methods
                )
                microsoft_allowed = (
                    organization.auth_methods == "ALL_ALLOWED" or
                    "microsoft_oauth" in organization.allowed_auth_methods
                )

                return render_template(
                    "organizationLogin.html",
                    public_token=STYTCH_PUBLIC_TOKEN,
                    api_base=stytch_client.api_base.base_url,
                    org_name=organization.organization_name,
                    google_allowed=google_allowed,
                    microsoft_allowed=microsoft_allowed
                )
            ```

            On your frontend, give users the option to start an OAuth flow with a specific provider.  For example, if you want to support Google and Microsoft OAuth:

            * Add a "Login with Google" button that links to `${apiBase}/v1/public/oauth/google/discovery/start?slug=${organization_slug}&public_token=${public_token}`
            * Add a "Login with Microsoft" button that links to `${apiBase}/v1/public/oauth/microsoft/discovery/start?slug=${organization_slug}&public_token=${public_token}`
          </Step>
        </Steps>
      </Tab>
    </Tabs>
  </Tab>
</Tabs>
