Prompt
How do I add SSO to my SaaS app without rewriting our existing login flow?
Latest observation
You can add SSO without rewriting your existing login flow by treating SSO as another way to authenticate a user, then mapping the SSO result into your current session system.
Practical approach
1. Keep your current auth/session layer
Don’t replace your existing:
- user table
- session/cookie handling
- JWT issuance
- authorization checks
Instead, add a new “identity verification” path that ends by creating the same local session your app already uses.
2. Add an Identity Provider integration
Support one or more standard SSO protocols:
- OIDC/OAuth2: best default for modern SaaS
- SAML: common for enterprise customers
For most SaaS products, OIDC first is simpler unless enterprise customers specifically need SAML.
3. Add an external identity mapping table
Store a link between your local user and the SSO identity:
user_idprovider(okta,azuread,google, etc.)provider_user_id/subjecttenant/org_id- optional: email, domain, last_login
This lets your app know that an SSO login belongs to an existing user account.
4. Use SSO only as a login path
Your login page can offer:
- Email/password
- “Continue with SSO”
Both paths should converge here:
- authenticate user
- resolve to local user
- create local session
- redirect into app
5. Add account linking and provisioning
You’ll need a strategy for users who authenticate via SSO but don’t yet exist locally:
- Just-in-time provisioning: create the account on first login
- Invite-only: require pre-created org membership
- Auto-link by verified email domain: common, but do this carefully
For enterprise SaaS, it’s usually safer to require the user to already be in the org or be invited.
6. Gate SSO by organization
In multi-tenant SaaS, SSO is usually enabled per organization:
- Org A uses password auth
- Org B uses Okta via SAML
- Org C uses Azure AD via OIDC
This avoids affecting all users and keeps rollout incremental.
7. Handle user matching carefully
Preferred matching order:
- exact SSO identity match
- linked local account
- verified email match
- fallback to account creation or error
Avoid auto-linking solely on email unless:
- email is verified by the IdP
- you trust the provider
- you’ve defined the policy clearly
8. Add a separate SSO callback endpoint
Keep the new logic isolated:
/auth/sso/start/auth/sso/callback/auth/saml/acs
These endpoints should eventually call your existing “log user in” function.
Minimal migration pattern
A good low-disruption design looks like this:
- Existing password login remains unchanged
- Add new SSO authentication endpoints
- After SSO validation, call the same internal function you use after password login:
create_session(user_id)
- Store SSO linkage in a new table
- Enable SSO per tenant/org
Implementation tips
If you want the fastest path
Use an auth broker/managed provider:
- Auth0
- Clerk
- WorkOS
- FusionAuth
- Okta/Auth0 enterprise features
These can reduce the complexity of handling SAML/OIDC, just-in-time provisioning, and org-based routing.
If you build it yourself
Use libraries for protocol handling:
- OIDC: standard OAuth/OIDC client libraries
- SAML: mature SAML libraries for your framework
Do not hand-roll protocol parsing if you can avoid it.
Security considerations
- Require PKCE for OIDC browser flows
- Validate issuer, audience, nonce, and signature
- Enforce email verification before linking accounts
- Support MFA policies from the IdP, but don’t assume they exist unless validated
- Log all SSO login attempts and linking events
- Allow admins to disable SSO per tenant and revoke links
Recommended rollout plan
- Add user↔SSO identity mapping table
- Add OIDC support for one provider
- Add org-level SSO configuration
- Keep existing login flow intact
- Add SSO login button and callback
- Add account linking/provisioning rules
- Later add SAML if enterprise customers need it
If you want, I can sketch a concrete architecture for your stack (e.g. Node/Express, Rails, Django, Next.js, Go) and show the exact endpoints and database tables.