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 and Organization-specific authentication flows are supported.
Discovery authentication
Organization-specific 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 they are trying to access.
In your application’s UI, use oauth.discovery.$provider.start() to allow users to begin the OAuth Discovery flow.
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>;};
2
Handle the OAuth callback
Stytch will send a callback to the Discovery Redirect URL you specified in the Stytch Dashboard. Exchange the token for a list of Discovered Organizations that the user can choose to log into.
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.
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.
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.
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 and Organization-specific authentication flows are supported.
Discovery authentication
Organization-specific 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 they are trying to access.
Stytch will make a callback to the Discovery Redirect URL that you specified in the Stytch Dashboard. Handle the callback and authenticate the token.
Python
@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 )
2
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.
3
Handle organization selection
Create routes to handle logging into an existing Organization or creating a new Organization.
@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()
4
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.
This will automatically redirect your browser to the OAuth provider to start the flow.
5
(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}
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.
Stytch will make a callback to the Login or Signup Redirect URL. Handle the callback and authenticate the token.
Python
@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()
2
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.
This will automatically redirect your browser to the specified OAuth provider to start the flow.
3
(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.
@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}
⌘I
Assistant
Responses are generated using AI and may contain mistakes.