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

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

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.";

## Authentication flow

```mermaid theme={null}
sequenceDiagram
    participant Browser
    participant App as Your Application Logic
    participant Stytch
    participant IDP as Workflow Idp

    Browser->>App: User initiates SSO login
    App->>Stytch: Call sso.start()
    Stytch-->>App: Returns redirect URL
    App-->>Browser: Follow redirect URL
    Browser->>IDP: Redirects to IdP
    IDP<<-->>Browser: User authenticates with IdP
    IDP<<-->>Stytch: Stytch performs SSO handshake with IdP
    Stytch-->>Browser: Redirect to Login or Signup Redirect URL with token
    Browser-->>App: Extract sso_token from URL
    App->>Stytch: Call sso.authenticate() with sso_token
    Stytch->>App: Member logged in<br/>Returns Member info & Session
```

***

<Note>
  Before you begin, make sure you've completed the [SSO provider setup steps](/multi-tenant-auth/authentication/sso/provider-setup).
</Note>

## Overview

<Tabs>
  <Tab title="Headless frontend SDK">
    This guide walks through integrating SSO 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 [SSO provider setup guide](/multi-tenant-auth/authentication/sso/provider-setup)
        2. Enable the Frontend SDKs in [your Stytch Dashboard](https://stytch.com/dashboard/sdk-configuration)

        ### Implementation

        <Steps>
          <Step title="Discover available SSO Connections">
            If you have a centralized login page, prompt the user for their email and call `sso.discoverConnections`.

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

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

                const discoverSSOConnections = (email) => {
                  stytch.sso.discoverConnections(email);
                };

                return <button onClick={() => discoverSSOConnections(email)}>Continue</button>;
              };
              ```
            </CodeGroup>

            The `sso.discoverConnections()` method returns an array of SSO Connections. Use the `display_name` and `idp_type` to render the available options, then pass the selected `connection_id` into the next step.
          </Step>

          <Step title="Start the SSO flow">
            Use the selected `connection_id` to initiate the SSO flow.

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

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

                const startSSO = () =>
                  stytchClient.sso.start({
                    connection_id: connectionId,
                  });

                return <button onClick={startSSO}>Log in with SSO</button>;
              };
              ```

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

                document.getElementById('login-with-sso').onclick = () => stytch.sso.start({
                  connection_id: 'saml-connection-test-51861cbc-d3b9-428b-9761-227f5fb12be9',
                });
              </script>

              <button id="login-with-sso">Login with SSO</button>
              ```
            </CodeGroup>

            The user will be redirected to their IdP to authenticate.
          </Step>

          <Step title="Handle the SSO callback">
            After the SSO handshake, Stytch redirects to your Login or Signup Redirect URL with a token in the URL. Call `sso.authenticate` to finish the login process.

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

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

                useEffect(() => {
                  if (session) {
                    window.location.href = 'https://example.com/profile';
                  } else {
                    const token = new URLSearchParams(window.location.search).get('token');
                    stytchClient.sso.authenticate({
                      sso_token: token,
                    });
                  }
                }, [stytchClient, session]);

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

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

                const token = new URLSearchParams(window.location.search).get('token');
                stytch.sso.authenticate({
                  sso_token: token
                });
              </script>
              ```
            </CodeGroup>

            The Stytch frontend SDK will store `stytch_session_token` and `stytch_session_jwt` in cookies for you. See [session cookie management](/api-reference/b2b/frontend-sdks/vanilla-js/resources/cookies-and-session-management).
          </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 [SSO provider setup guide](/multi-tenant-auth/authentication/sso/provider-setup), including creating an Organization.
        2. Enable the Frontend SDKs in [your Stytch Dashboard](https://stytch.com/dashboard/sdk-configuration)

        ### Implementation

        <Steps>
          <Step title="Fetch Organization SSO Connections">
            Use the Organization slug to fetch SSO Connections and render them in your UI.

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

            export const OrganizationLoginPage = ({ slug }) => {
              const stytch = useStytchB2BClient();
              const [organization, setOrganization] = useState();
              useEffect(() => {
                stytch.organization
                  .getBySlug({ organization_slug: slug })
                  .then((response) => setOrganization(response.organization));
              }, [stytch, slug]);

              if (organization === undefined) {
                return <p>Loading...</p>;
              }

              if (!organization) {
                return <p>No organization found for {slug}</p>;
              }

              const ssoConnections = organization.sso_active_connections;

              // render UI
            };
            ```
          </Step>

          <Step title="Start the SSO flow">
            Call `sso.start()` using the selected `connection_id`.

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

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

              const startSSO = (connectionId) =>
                stytchClient.sso.start({
                  connection_id: connectionId,
                });

              return <button onClick={() => startSSO(organization.default_connection_id)}>Log in with SSO</button>;
            };
            ```
          </Step>

          <Step title="Handle the SSO 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 { Navigate } from "react-router-dom";

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

                useEffect(() => {
                  if (session) {
                    <Navigate to="/profile" />;
                  } else {
                    const token = new URLSearchParams(window.location.search).get('token');
                    stytchClient.sso.authenticate({
                      sso_token: token,
                    });
                  }
                }, [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');

                const token = new URLSearchParams(window.location.search).get('token');
                stytch.sso.authenticate({ sso_token: token });
              </script>
              ```
            </CodeGroup>
          </Step>
        </Steps>
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Backend SDK">
    This guide walks through integrating SSO using Stytch's backend SDKs or Direct API. This approach handles all authentication logic on your backend.

    <Tabs>
      <Tab title="Discovery authentication">
        ### Prerequisites

        Complete the steps in the [SSO provider setup guide](/multi-tenant-auth/authentication/sso/provider-setup).

        ### Implementation

        <Steps>
          <Step title="Configure the callback route">
            Stytch will make a callback to your Redirect URL. Handle `stytch_token_type=sso` 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 == "sso":
                    resp = stytch_client.sso.authenticate(sso_token=request.args["token"])
                    if resp.status_code != 200:
                        return "Authentication error"
                else:
                    return "unsupported auth method"

                member = resp.member
                session["stytch_session"] = resp.session_jwt
                return member.json()
            ```
          </Step>

          <Step title="Initiate SSO">
            Test the SSO flow by navigating to:

            ```text theme={null}
            https://test.stytch.com/v1/public/sso/start?connection_id={connection_id}&public_token={public_token}
            ```
          </Step>

          <Step title="(Optional) Build a connection selector">
            If multiple SSO Connections exist, show users a list based on their Organization.

            ```python theme={null}
            @app.route("/org/<string:slug>", methods=["GET"])
            def org_index(slug: str):
                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]
                return render_template(
                    "organizationLogin.html",
                    public_token=STYTCH_PUBLIC_TOKEN,
                    org_name=organization.organization_name,
                    sso_connections=organization.sso_active_connections
                )
            ```
          </Step>
        </Steps>
      </Tab>
    </Tabs>
  </Tab>
</Tabs>
