Platform auth integration
MVS operator apps (the platform-admin surface and its kin) authenticate
against a separate auth service from tenant users. It is live at
https://c2-auth.mvscloud.com and serves a Better Auth instance with its own
session, distinct from central tenant auth at c-auth.mvscloud.com.
Two surfaces, two sessions. Tenant users authenticate at
c-auth.mvscloud.com (see the
OIDC integration guide);
MVS operators authenticate at c2-auth.mvscloud.com. They share the same
registrable domain for cookie scoping but are independent Better Auth
instances with separate BETTER_AUTH_SECRETs.
1. The model — redirect, don’t fetch
c2-auth.mvscloud.com is a dedicated Vercel project (owned by mvs-auth) that
hosts the platform-auth Better Auth handler directly at
/api/platform-auth/*. An operator app does not stand up its own auth
handler and does not make a cross-origin auth fetch. Instead:
- The operator app (e.g.
c2.mvscloud.com) redirects the operator tohttps://c2-auth.mvscloud.com/loginto authenticate. - Platform auth signs them in (Okta SSO is the primary path — see the Okta SSO setup runbook).
- The session cookie is minted with
Domain=mvscloud.com(cross-subdomain), so the operator app reads the shared.mvscloud.comsession cookie directly — no token exchange, no cross-origin call.
2. Cookie scoping
The platform-auth base URL must resolve to a mvscloud.com host. In
production PLATFORM_AUTH_BASE_URL is left unset so the code defaults to
https://c2-auth.mvscloud.com. Never point it at a *.vercel.app
deployment URL: the browser rejects a Domain=mvscloud.com cookie on a
vercel.app origin (sign-in fails outright), and the rate-limiter treats a
vercel.app host as non-production and silently disables itself.
3. Trusted origins
Platform auth trusts the MVS estate’s registrable domains for its CSRF / origin
checks — any *.mvscloud.com subdomain is trusted. An operator app served from
a mvscloud.com subdomain needs no special configuration; the shared-cookie
redirect model works out of the box. If your operator surface lives on a
different registrable domain, it must be added to the trusted-origins
allowlist server-side — coordinate with the operator (it is not self-service).
Operator-auth enforcement (PLATFORM_SSO_ONLY) — zero-password, Okta-SSO +
passkey-only — is coded but not yet enforced in production (pending Okta
config and operator passkey enrollment). Until then, password login is
temporarily on. See the
Operations page for the
enforcement levers.
4. Client library
In-monorepo operator apps use the platform variant of the auth client:
This wraps Better Auth’s React client against the platform-auth host. It is for
operator session/cookie auth on *.mvscloud.com — it is not an OIDC
genericOAuth client.
5. OIDC for operator apps
Beyond the shared session cookie above, c2-auth.mvscloud.com is now a full
OIDC provider (an operator IdP). Operator apps can register a
platform_oauth_client (the isolated platform table, keyed to PlatformUser —
not central’s oauth_client) and run the same authorization-code + PKCE flow
tenant apps use at c-auth.mvscloud.com. Use this when an operator app runs its own Better
Auth instance and consumes c2-auth as an upstream OIDC provider, rather than
reading the shared cookie directly.
This is shipped and live in production. The platform IdP is a second,
isolated OIDC provider (its own platform_oauth_* tables and platform_jwks,
keyed to PlatformUser). Register operator-app clients via the
self-service client registration API/IAT flow
(platform surface) or the operator CLI — see the
Operator-app OIDC integration guide for the
full walkthrough: discovery, the genericOAuth provider config (providerId: "c2-auth"), redirect URIs, claims, and token verification.