Skip to main content

Google + Microsoft SSO (OAuth v1)

FieldValue
StatusDeferred. Not included in any current tier.
OwnerUnassigned
Target reposattunelogic-api, attunelogic-service, attunelogic-mobile
RelatedMonetization & Tier Packaging (v1), Feature Roadmap Index
Last updated2026-04-23

Status banner: Google + Microsoft OAuth SSO was removed from the public Pro roadmap in v1. Passport-local (email + password + optional MFA) is the only production login path today. SAML SSO stays Enterprise-only and is a separate proposal.


Why this was removed from v1

  • Each provider is a ~1 to 1.5 week lift on its own: configure the OAuth app, add passport strategy, build "link to existing email" onboarding, add the login buttons to the service web sign-in page, then handle the redirect-URI story for mobile via expo-auth-session.
  • Two providers × two surfaces (web + mobile) + the account-linking UI blows past the launch-week budget.
  • Not a win for pricing differentiation at launch either — most small trucking ICPs don't have corporate Google/MS tenants. SSO becomes a legitimate Pro-tier hook once we move up-market.

What shipping this requires

Provider setup

  • Google: Google Cloud project + OAuth consent screen verification for openid email profile (the minimal non-sensitive scope set, which avoids Google's slow security review).
  • Microsoft: Azure App Registration. Multi-tenant app (common authority) so any MS tenant can sign in. Scopes: openid profile email offline_access.
  • Per-environment redirect URIs:
    • service.attunelogic.com/auth/callback/google
    • service.attunelogic.com/auth/callback/microsoft
    • attunelogic://auth/callback/google (mobile deep link via expo-auth-session)
    • attunelogic://auth/callback/microsoft

Data model

  • Extend User:
    • authProviders: [{ provider: "local" | "google" | "microsoft", providerUserId: string, linkedAt: Date }]
  • Existing email remains the human identity key; all providers link to the same user row by normalized email match on first login, subject to admin confirmation the first time.

API + passport strategies

  • passport-google-oauth20 — existing passport setup in attunelogic-api/src/services/auth/*.
  • passport-azure-ad (OIDC strategy against https://login.microsoftonline.com/common/v2.0).
  • Middleware:
    • GET /api/v1/auth/oauth/:provider/start — issues state + redirect.
    • GET /api/v1/auth/oauth/:provider/callback — exchanges code, links or creates user, issues session.
  • Account linking: if the incoming provider email matches an existing local-auth user, require password confirmation OR email-link confirmation before attaching the new provider. Never silently merge accounts on email alone.

Service web UI

  • Sign-in page: "Sign in with Google" + "Sign in with Microsoft" buttons under the existing email/password form.
  • Account settings: "Linked accounts" row listing linked providers with an Unlink button (refuses to remove the last auth method).

Mobile UI

  • expo-auth-session flow on iOS + Android. Uses the universal-links / deep-link redirect URIs above.
  • Reuse the existing useAuth hook — SSO completion calls the same session-bootstrap endpoint after the code exchange.

Feature gating

  • sso.enabled feature flag — already reserved in the monetization proposal. Pro and Enterprise only.
  • On Starter and Growth, the SSO buttons on the sign-in page are hidden. Paid Enterprise SAML is a separate proposal.

Tests

  • Unit: provider-to-user linking precedence (email match, provider id match, no match → new user with confirmation email).
  • Integration (mocked OIDC): happy-path login, state mismatch rejection, email verification not-set rejection.
  • Tenant isolation: a linked provider identity on tenant A cannot impersonate a user in tenant B, even if the same email exists on both (multi-tenant email re-use is allowed in our data model).

Docs

  • Customer SSO setup guide.
  • Admin runbook for unlinking a compromised provider account.

Dependencies on existing infra

  • passport-local — already wired in src/services/auth. New strategies drop in beside it.
  • Session issuance — the existing session cookie + refresh flow is reused unchanged.
  • useAuth hook on mobile — already handles session bootstrap; SSO just feeds it.
  • Feature flag sso.enabled — already reserved.

Estimated timeline and risk

  • Effort: 1–1.5 weeks per provider for API + service web + mobile wiring. 2.5–3 weeks total for both.
  • Risk: Low-medium. The risk is almost entirely in the account-linking UX, not the OAuth itself. The first time a customer signs in with Google using an email that already has a local password, we MUST surface the linking confirmation correctly — getting that wrong is an account-takeover primitive.

Open questions

  • Do we want "SSO-only" as a per-tenant policy (force all users to sign in via a specific provider)? That's a meaningful enterprise feature that bumps us toward SAML territory.
  • Do we enforce email verification on first provider sign-in, or trust the provider's verification?
  • Do we ship Apple Sign-In alongside Google/Microsoft on iOS? (Apple requires it on App Store submissions that ship any third-party SSO button.)

Cross-references