Decisions and roadmap
ADR 0003: Convex Auth v2 as the shared identity plane
- Status: accepted
- Date: 2026-09-23
- Supersedes: 0002-clerk-identity-boundary.md
- Amended by: 0004-exo-id-central-identity-provider.md — Exo is the sole OAuth client and identity provider; apps are relying parties.
Context
ADR 0002 chose Clerk as the authentication provider for the Exo identity plane, with Exo retaining authorization. Since then, two things changed:
- Convex Auth reached a v2 architecture (components: a core that mints RS256 JWTs and owns sessions, plus provider components for password/username, OAuth, passkeys, email). Per the Convex team it is stable enough for deployment now and reaches GA by Q4; Interspace product scale stays small until then, so preview risk is acceptable.
- Clerk charges per MAU and makes a proprietary vendor the default login surface for every Exo-owned app, while all of our app state already lives in Convex. Keeping identity in the same system that owns the data removes a vendor, a webhook surface, and a whole identity-mapping layer.
Rampart shipped Convex Auth v2 with Google and Apple OAuth in September 2026 and is the reference implementation for the platform pattern.
Decision
Convex Auth v2 is the shared identity plane for every Interspace application. Exo-owned apps use it for authentication; Exo retains authorization exactly as before (resource-local grants, roles, capabilities, validity, revocation).
The platform pattern, proven in Rampart:
Mount the auth core component (Superseded by ADR 0004: only Exo mounts the core and provider components; apps verify Exo ID tokens withhttpPrefix: "/auth",AUTH_PRIVATE_KEY/AUTH_JWKSenv) plus whichever provider components the app needs (password/username, OAuth Google/Apple, passkeys) in the app'sconvex/convex.config.ts.customJwtand mount none.convex/auth.config.tsverifies core JWTs ascustomJwtagainst the deployment JWKS at${CONVEX_SITE_URL}/auth/.well-known/jwks.json.- Each provider wires
setup*withattachUserCallbacks({ createUser }); the app owns itsuserstable and the profile mapping. Provider components own accounts/sessions. - Clients use
@convex-dev/auth/react(ConvexAuthProviderwithapi: { refreshSession, signOut }) and the provider hooks (useSignInWithGoogle,useSignInWithApple, password helpers). Route protection is client-side (Authenticated/Unauthenticated); v2 ships no Next.js middleware helper. - Backend identity is always derived server-side (
getAuthUserIdorctx.auth.getUserIdentity().tokenIdentifier); never accept a caller-supplied owner ID.
A separate identity plane for a client application's customers remains allowed under the same conditions as ADR 0002 (independently owned user population, legal boundary, or identity adapter) — implemented with Convex Auth v2, not Clerk.
Consequences
- Clerk is no longer the platform authentication provider. Clerk dependencies are removed from each app as it migrates; apps with existing Clerk user populations (Construct, Observatory) need a per-app user-mapping or re-login plan before cutover.
OAuth provider approval is platform-level: the approved catalog (Google, GitHub; Apple per-app) is defined inSuperseded by ADR 0004: the provider catalog (Google, GitHub; Apple when added) is mounted once, at Exo. There is no per-app Apple or any other per-app provider.docs/exo-auth-contract.mdin Construct and mounted uniformly by every Exo app. A provider added for one app is added to the catalog and swept into every app.OAuth client registration (Google Cloud Console, GitHub, Apple Developer) is per-provider platform setup, recorded in the app's env contract; Convex Auth does not broker those registrations.Superseded by ADR 0004: Exo holds the only OAuth client registrations; apps never touch Google Cloud Console, GitHub OAuth settings, or Apple Developer.- v2 is pre-GA: pin the alpha version per app, track the
rebootbranch, and budget a version-bump pass before Q4. Upgrades are contained toconvex/auth.ts,convex/auth.config.ts,convex/convex.config.ts, and the client provider. - The ADR 0002 migration gate is retired with it; identity verification moves to per-app auth/isolation tests plus the Convex Auth component contract tests.
- Payload local authentication in EXO itself remains the admin fallback until the Convex-native frontend ships; this ADR governs the app identity plane, not Payload's internal admin login.