The Discovery flow is designed for centralized login pages where users authenticate before selecting which Organization to access.Start the OAuth flow
Redirect the user to start the OAuth flow. This must be done in the browser:Example URL (Google):https://test.stytch.com/v1/b2b/public/oauth/google/discovery/start?public_token=YOUR_PUBLIC_TOKEN&discovery_redirect_url=https://yourapp.com/authenticate
Query parameters:
public_token: Your Stytch public token
discovery_redirect_url: Where to redirect after OAuth completes
Supported providers:
- Google:
/oauth/google/discovery/start
- Microsoft:
/oauth/microsoft/discovery/start
- GitHub:
/oauth/github/discovery/start
- Slack:
/oauth/slack/discovery/start
- HubSpot:
/oauth/hubspot/discovery/start
The user will authenticate with the provider and be redirected back to your discovery_redirect_url with a token query parameter. Authenticate the OAuth token
After the redirect, exchange the OAuth token for an intermediate session:curl --request POST \
--url https://test.stytch.com/v1/b2b/oauth/discovery/authenticate \
--header 'Content-Type: application/json' \
--user 'PROJECT_ID:SECRET' \
--data '{
"discovery_oauth_token": "hdPVZHHX0UoRa7hJTuuPHi1vlddffSnoweRbVFf5-H8g"
}'
Parameters:
discovery_oauth_token: The token from the redirect URL query parameter
Response:{
"status_code": 200,
"request_id": "request-id-test-...",
"intermediate_session_token": "SeiGwdj5lKkrEVgcEY3QNJXt6srxS3IK2Nwkar6mXD4=",
"email_address": "user@example.com",
"full_name": "Jane Doe",
"provider_type": "Google",
"provider_tenant_id": "1234567",
"discovered_organizations": [
{
"organization": {
"organization_id": "organization-test-...",
"organization_name": "Acme Corp",
"organization_slug": "acme-corp"
},
"membership": {
"type": "eligible_to_join_by_email_domain",
"details": {}
}
}
]
}
Exchange the intermediate session
After the user selects an organization, exchange the intermediate session token for a full session:curl --request POST \
--url https://test.stytch.com/v1/b2b/discovery/intermediate_sessions/exchange \
--header 'Content-Type: application/json' \
--user 'PROJECT_ID:SECRET' \
--data '{
"intermediate_session_token": "SeiGwdj5lKkrEVgcEY3QNJXt6srxS3IK2Nwkar6mXD4=",
"organization_id": "organization-test-...",
"session_duration_minutes": 60
}'
Response:{
"status_code": 200,
"request_id": "request-id-test-...",
"member_id": "member-test-...",
"session_token": "mZAYn5aLEqKUlZ_Ad9U_fWr38GaAQ1oFAhT8ds245v7Q",
"session_jwt": "eyJhbGc...",
"member": { /* member object */ },
"organization": { /* organization object */ },
"session": { /* session object */ }
}
The Discovery flow returns an intermediate_session_token which must be exchanged for a full session after the user selects their organization.
The Organization flow is for organization-specific login pages where the organization context is already known (e.g., acme.yourapp.com).Start the OAuth flow
Redirect the user to start the OAuth flow for a specific organization. This must be done in the browser:Example URL (Google):https://test.stytch.com/v1/b2b/public/oauth/google/start?public_token=YOUR_PUBLIC_TOKEN&organization_id=organization-test-...&login_redirect_url=https://acme.yourapp.com/authenticate&signup_redirect_url=https://acme.yourapp.com/authenticate
Query parameters:
public_token: Your Stytch public token
organization_id: The organization’s ID (either this or slug required)
slug: The organization’s slug (alternative to organization_id)
login_redirect_url: Where to redirect existing members
signup_redirect_url: Where to redirect new members
Supported providers:
- Google:
/oauth/google/start
- Microsoft:
/oauth/microsoft/start
- GitHub:
/oauth/github/start
- Slack:
/oauth/slack/start
- HubSpot:
/oauth/hubspot/start
The user will authenticate with the provider and be redirected back with a token query parameter. Authenticate the OAuth token
After the redirect, exchange the OAuth token for a session:curl --request POST \
--url https://test.stytch.com/v1/b2b/oauth/authenticate \
--header 'Content-Type: application/json' \
--user 'PROJECT_ID:SECRET' \
--data '{
"oauth_token": "hdPVZHHX0UoRa7hJTuuPHi1vlddffSnoweRbVFf5-H8g",
"session_duration_minutes": 60
}'
Parameters:
oauth_token: The token from the redirect URL query parameter
session_duration_minutes: (Optional) Session lifetime in minutes (default: 60)
Response:{
"status_code": 200,
"request_id": "request-id-test-...",
"member_id": "member-test-32fc5024-9c09-4da3-bd2e-c9ce4da9375f",
"organization_id": "organization-test-07971b06-ac8b-4cdb-9c15-63b17e653931",
"session_token": "mZAYn5aLEqKUlZ_Ad9U_fWr38GaAQ1oFAhT8ds245v7Q",
"session_jwt": "eyJhbGc...",
"member_authenticated": true,
"provider_type": "Google",
"provider_subject": "10769150350006150715113082367",
"provider_values": {
"access_token": "example-access-token",
"refresh_token": "example-refresh-token",
"id_token": "example-id-token",
"scopes": ["openid", "email", "profile"]
},
"member": { /* member object */ },
"organization": { /* organization object */ },
"member_session": { /* session object */ }
}
Use the session
Store the session_token or session_jwt to authenticate future API requests. The provider_values object includes OAuth tokens you can use to call the provider’s APIs on behalf of the user.
If MFA is required or the OAuth provider doesn’t verify email, member_authenticated will be false and an intermediate_session_token will be returned. Complete the required authentication step to get a full session.