Social SSO + Stripe + SDK Deep Dive
End-to-end integration reference for Doorman-managed auth and billing in a third-party app.
Overview
This guide covers the full path from sign-in to paid entitlement: provider-first social login, optional enterprise domain discovery, Stripe recurring billing setup, and runtime SDK integration.
- Third-party app handles login/register UI.
- Doorman handles OAuth/OIDC and identity session orchestration.
- Stripe handles payment collection and provider-native billing state.
- Doorman remains the source of truth for entitlement gating.
Architecture
Third-party app (sample-spa) -> Hydra authorize -> Doorman /oauth/login Doorman /oauth/login -> control-api session check Doorman /oauth/login -> control-api external SSO broker (org provider config) External provider (Google/Microsoft/GitHub) -> control-api callback -> Hydra login accept Third-party app -> control-api app-key billing APIs -> Stripe control-api + workers -> subscription sync + usage export -> Stripe
Runtime endpoints: Control API: https://doorman.f1cs-dev.it, Hydra issuer: https://doorman.f1cs-dev.it/oauth2.
Provider-first SSO (Google/Microsoft/GitHub)
This is the consumer-style flow: user clicks a provider button and goes through Doorman's app-scoped provider broker. It does not require domain mapping.
- In Doorman dashboard, create org identity provider records for the app org (issuer URL, client ID, client secret).
- Configure provider apps with callback URL:
- All providers (Google/Microsoft/GitHub):
https://doorman.f1cs-dev.it/api/oauth/sso/callback
- All providers (Google/Microsoft/GitHub):
- From app login, Doorman resolves available org providers for that app and either:
- auto-starts when a provider hint resolves, or
- auto-starts when exactly one provider exists, or
- shows provider picker at `/oauth/login`.
- Direct API start endpoint:
curl -i -sS "https://doorman.f1cs-dev.it/api/oauth/sso/start?login_challenge=<challenge>&provider_id=<provider_id>"
This flow is app/org-scoped and does not depend on global Kratos social provider configuration.
Google setup for sample-spa (local)
- In Google Cloud Console, create OAuth client credentials with app type Web application.
- Set Google authorized redirect URI to:
https://doorman.f1cs-dev.it/api/oauth/sso/callback. - In Doorman dashboard, for the same org that owns the sample-spa app, create identity provider:
- Type: OIDC
- Name: google (or Google)
- Issuer URL:
https://accounts.google.com - Client ID/secret: from Google OAuth client credentials
- Set control-api public URL in env and restart control-api:
# services/control-api/.env CONTROL_API_PUBLIC_URL=https://doorman.f1cs-dev.it
- In sample-spa, click Login with Google. Doorman should broker provider login and return to
/callbackin the app.
If you use 127.0.0.1 instead of localhost anywhere, register that exact callback host in Google and keep it consistent across control-api URL, browser URL, and provider config.
Domain-discovery SSO (enterprise routing)
This flow maps email domain to org identity provider. Use it for enterprise environments where `@company.com` should route deterministically.
- Create org identity provider in Doorman.
- Map domain(s) on provider (for example `acme.com`).
- Resolve provider from email:
curl -sS "https://doorman.f1cs-dev.it/api/sso/resolve-provider?email=user@acme.com"
- App starts OIDC redirect with resolver context (`doorman_provider_id`, `doorman_org_id`, `login_hint`).
`provider_not_found` is expected for unmapped domains and should fall back to password/registration path.
Stripe connection
Configure Stripe at control-api level first. Without this, checkout and status operations cannot call Stripe.
# services/control-api/.env STRIPE_DRY_RUN=0 STRIPE_API_BASE=https://api.stripe.com STRIPE_SECRET_KEY=sk_test_... STRIPE_WEBHOOK_SIGNING_SECRET=whsec_...
Webhook endpoint: POST /api/billing/stripe/webhook with stripe-signature provider signature verification.
Plan, customer, and meter mapping
Stripe recurring requires three mapping layers. Missing one causes explicit errors.
- Plan component mapping:
plan_id+ component kind -> Stripeprice_...in/api/apps/:appId/billing/provider-plan-components. - Customer mapping:
tenant_id->cus_...in/api/apps/:appId/billing/ensure-customeror bootstrap path. - Meter mapping for usage export workers:
/api/apps/:appId/billing/provider-meters.
`external_price_id` must be a Stripe price ID (`price_...`), not a numeric amount.
Third-party SDK integration pattern
Use `@doorman/react-sdk` to centralize auth, SSO, billing, and generic authorization mechanics.
For fastest onboarding, embed DoormanAuthPanel in your app login page. It includes register/login + direct provider SSO buttons + domain-discovery SSO.
import {
DoormanAuthPanel,
DoormanProvider,
RequirePolicy,
buildDoormanOidcClientSettings,
createDoormanSsoClient,
createDoormanBillingClient,
createDoormanServerContext,
requireServerPolicy,
handleDoormanOidcCallback
} from "@doorman/react-sdk";<DoormanAuthPanel
userManager={userManager}
kratosPublicUrl="http://localhost:4433"
controlApiBase="https://doorman.f1cs-dev.it"
/>- Authenticate user (provider-first, discovery, or password).
- Handle callback idempotently with SDK helper.
- Resolve tenant for identity (`sub`).
- Bootstrap tenant only when missing; ensure customer for existing tenant.
- Create checkout session and redirect to Stripe.
- Poll subscription status and gate paid features by `is_active`.
- Parse Doorman claims and enforce tenant permissions with SDK policy helpers.
- Ingest usage events.
<DoormanProvider user={user} appId="APP_ID">
<RequirePolicy
rule={{ type: "permission", permission: "resources:read" }}
fallback={<NoAccess />}
>
<Workspace />
</RequirePolicy>
</DoormanProvider>React gates are for UX only. Protected mutations still need server-side checks with requireServerPolicy or equivalent app-side logic.
SDK/API contract map
Use this mapping when handing the SDK to app teams. It keeps auth context explicit and shows where each SDK call lands in control-api/Swagger.
For strict implementation requirements and pass/fail integration criteria, use the dedicated contract page:/docs/api-contract.
- Swagger UI:
https://doorman.f1cs-dev.it/docs/api/ - OpenAPI JSON:
https://doorman.f1cs-dev.it/docs/api/json - Checked contract:
services/control-api/contracts/control-api.openapi.json createDoormanBillingClientmethods usex-doorman-api-keyapp-key endpoints.createDoormanSsoClientmethods use browser session cookies (owner/org-admin context).parseDoormanClaims,can,RequirePolicy, andrequireServerPolicyare local SDK helpers; they do not call control-api.
@doorman/react-sdk (billing) -> control-api
listPlans -> GET /api/apps/:appId/billing/plans
resolveTenantForIdentity -> POST /api/apps/:appId/billing/resolve-tenant
bootstrapTenant -> POST /api/apps/:appId/billing/bootstrap-tenant
ensureBillingCustomer -> POST /api/apps/:appId/billing/ensure-customer
createCheckoutSession -> POST /api/apps/:appId/billing/checkout-sessions
getSubscriptionStatus -> GET /api/apps/:appId/billing/subscriptions/:subscriptionId/status
getCurrentSubscriptionStatus -> GET /api/apps/:appId/billing/subscriptions/current?tenant_id=...
cancelSubscription/reactivateSubscription/changeSubscriptionPlan/createBillingPortalSession ->
POST /api/apps/:appId/billing/subscriptions/:subscriptionId/{cancel|reactivate|change-plan|portal-session}
ingestUsageEvent -> POST /api/apps/:appId/events/ingest
getUsageSummary/getAgentUsageSummary -> GET /api/apps/:appId/billing/usage-summary{,/agents}
getCostPreview -> GET /api/apps/:appId/billing/cost-preview
getCapacityUtilization -> GET /api/apps/:appId/billing/utilization
listAgents/createAgent/rotate/revoke/deactivate/delete ->
/api/apps/:appId/service-accounts...@doorman/react-sdk (authorization) -> local app/runtime getDoormanClaimsFromUser -> parse OIDC user access_token/id_token/profile createDoormanPolicyContext -> choose active tenant can / requirePolicy -> evaluate roles, permissions, entitlements, actor type DoormanProvider / RequirePolicy -> client UX gates createDoormanServerContext / requireServerPolicy -> server action/API enforcement
Service-account lifecycle endpoints accept both app-key runtime callers and Doorman dashboard session callers.
Agent and service-account management
For app backends and agent-like entities, Doorman provides app-scoped service account management. These entities are not sample-spa-only records: they are persisted in Doorman and can be used for usage attribution and plan-cap enforcement.
- Service-account lifecycle API:
/api/apps/:appId/service-accountsplus rotate/revoke/deactivate/delete actions for app-key and owner/admin session contexts. - Usage attribution by entity:
/api/apps/:appId/events/ingestwith optionalagent_idand readback via/api/apps/:appId/billing/usage-summary/agents. - Cap enforcement:
service_accountsandmember_seatsmeter limits block over-cap create/assignment paths deterministically.
Expected data state
After first successful bootstrap for a new app user:
- Identity exists and has Doorman session.
- Identity has a default tenant link.
- Tenant membership exists.
- Tenant app membership exists (role auto-selection/fallback).
- Stripe customer mapping exists for org + tenant.
Subscription is created when checkout session is created, not at bootstrap.
Troubleshooting matrix
- Google
Access blocked: This app's request is invalid: verify OAuth client type is Web application and redirect URI matches exactlyhttps://doorman.f1cs-dev.it/api/oauth/sso/callback. - Google callback mismatch by host: do not mix
localhostand127.0.0.1unless both are configured everywhere. provider_not_found: domain-discovery mapping missing.- Provider unavailable for app login: org/provider mapping missing for the OAuth client app, or provider hint did not match configured provider.
missing_provider_plan_base_component_mapping: map a base plan component to Stripe price.missing_provider_customer_mapping: ensure customer mapping for tenant.- Checkout `line_items[0][price]` error: wrong value, must be
price_...ID. - Subscription stuck pending: verify webhook delivery/secret/signature and status polling against same subscription ID.
- Usage not exported: verify provider meter mapping and run
aggregate+sync-usageworkers.
Execution checklist
- Create org identity provider entries in Doorman dashboard.
- Set provider callback URI to
https://doorman.f1cs-dev.it/api/oauth/sso/callback. - Configure Stripe credentials and webhook on control-api.
- Map Doorman plans to Stripe prices.
- Map/create tenant customers.
- Run provider-first Google login end to end.
- Run domain-discovery mapped and unmapped paths.
- Complete checkout and wait for active entitlement.
- Send usage event and verify ingestion/export pipeline.