[Ever ID] Optional sign-in with Ever ID, as a plugin, default off
Epic: APW-12 (Ever Works) · Wave: 3 (P3, production last) · Tracking: tasks T35, T39, T40, T41, T42 in
../tasks.md · Design: ../cross-platform.md §5
Re-verify before filing. Paths below were read on
developon 2026-09-17. Gauzy is the only production platform, so this issue is deliberately conservative: server-side first, default off, its own review, and the production flag in a separate owner-approved change with backups verified first.
What and why
People who use several Ever products should be able to arrive at Gauzy already knowing who they are, without Gauzy giving up its own accounts. Ever ID is an addition:
- Gauzy keeps e-mail/password, magic code and every social strategy exactly as they are.
- Gauzy keeps its own user database and its own sessions; a person may exist in both, and nothing is merged.
- With the flags off, Gauzy behaves exactly as it does today — including every existing test.
Scope
- A provider plugin, not core. A new
packages/plugins/<name>(@gauzy/plugin-*) exporting a NestJS module that carries its own Passport strategy over a generic OpenID Connect client, its own guard, its own controller and its own configuration (EVER_ID_ISSUER,EVER_ID_GAUZY_CLIENT_ID,EVER_ID_GAUZY_CLIENT_SECRET, callback under${API_BASE_URL}/api/auth/ever-id/callback). Registered by one import plus one array entry inapps/api/src/plugins.ts.packages/core,packages/auth/src/lib/internal.tsandpackages/configare not edited. - Server-side sign-in, default off.
FEATURE_EVER_ID_API, evaluated strictly as'true'inside the plugin. - Web sign-in with a code hand-off. The callback redirects with a one-time code — never a token, never a
session id — which the web exchanges on the same origin. Existing
routeRedirectbehaviour is untouched. - Connect / disconnect for an existing Gauzy user, on the profile page, with the same two decisions Ever Works has.
- Back-channel logout, ending only the sessions Ever ID opened.
- MCP authorization server sign-in through Ever ID, behind
MCP_AUTH_EVER_ID_ENABLED, in its own change. - The provider-plugin family (
zitadel,keycloak,supertokens,auth0) ships alongside: each is optional, independent, enabled by its own configuration and fails closed when unconfigured. The shipped Keycloak code is relocated into its plugin with behaviour unchanged — same exports, same'disabled'defaults, same routes — so a self-hoster who uses Keycloak today notices no difference. A SuperTokens plugin is added ("not to replace anything") so a self-hoster can run Gauzy with SuperTokens exactly as they can with Keycloak today.
Acceptance
- The criteria in
../cross-platform.md§7 underXP-G-01…XP-G-06, each mapped to the test file named there. - Existing suites pass unchanged with the flags off and on: the login smoke test, the login BDD feature and every configured social sign-in.
- The callback URL contains no token, no code belonging to another session, and no user identifier.
Production gate (separate change)
Backups verified per the operations runbook; every existing sign-in method exercised on stage before and after;
owner approval recorded; FEATURE_EVER_ID_LOGIN=true in production — and MCP_AUTH_EVER_ID_ENABLED=true in a
further separate change. Rollback is a flag flip.
Out of scope
- Replacing, deprecating or reordering any existing sign-in method.
- Migrating accounts, merging profiles or synchronising profile fields with Ever ID.
- Any behaviour change to the shipped Keycloak strategy beyond its relocation into a plugin.