M005 Context: Cutover + Decommission (Phase 5)¶
Epic: #2418 | Phase tracker: #2466 | Bundled legacy issues: #2441–#2443
Goal¶
Move SyRF production authentication from direct Auth0 SPA tokens to BFF cookies backed by the SyRF OpenIddict identity service, prove the migration is safe and reversible, remove Auth0 runtime dependencies only after four full weeks of measured fallback availability, and decommission the Auth0 tenant manually.
Corrected Starting State (2026-07-24)¶
The earlier phase record assumed that M004 had migrated production users and moved production to OpenIddict. That assumption is false:
https://signin.syrf.org.uk/.well-known/openid-configurationstill publishes Auth0 endpoints.https://syrf.org.uk/assets/data/appConfig.env.jsonstill reportsauthProvider=auth0.cluster-gitopshas identity service configuration for previews only. Staging and production identity applications are absent.- Staging and production API/Web values do not enable
BffAuthor configureIdentityService. - M004 delivered migration tooling, but a real-runtime password-reset-token path is not yet proven.
- Identity restore currently reports vulnerable SharpCompress and Snappier dependencies.
- Issue #2466 marks Phase 5 as not started and is the authoritative tracker.
The deployable code also has specific blockers that must be fixed before any environment receives identity traffic:
- Identity reads
Authentication:Google,SESSettings,OpenIddict:*,AppSettingsConfig:*, andIdentityDatabase:*, while the chart emits several incompatibleSYRF__Google,SYRF__SES, and secret-name-onlySYRF__OpenIddictkeys. Identity does not currently install theSYRF__environment provider. - The public OpenIddict issuer and trusted proxy/forwarded-header contract are not explicit.
- Campaign CLI DataProtection keys are process-local; a token is not guaranteed to redeem in another Identity process or after restart.
- BFF provider derivation misclassifies Auth0's custom domain, the combined selector still sees stale BFF cookies when BFF is disabled, and Redis namespaces can be reused across authority switches.
- Existing campaign/readiness reporting lacks Auth0 activity data and authoritative privileged/enabled/Google/locked denominators.
- BFF and migration logs currently expose identifiers, email addresses, session IDs, state nonces, or token-bearing response/link data in some branches.
- CSRF compares only host name; it does not enforce exact effective scheme, host, and port after trusted forwarding.
M005 therefore begins with executable application readiness, shared key persistence, security/rollback contracts, live-environment tooling, and migration controls. Auth0 code, packages, configuration, secrets, and the tenant remain intact until their explicit post-observation slices.
Scope¶
- Application readiness — Fix the complete Identity host/chart configuration contract, public issuer/proxy/basic readiness, then add shared encrypted DataProtection and its readiness contributor; establish explicit BFF provider/session semantics before telemetry/log changes; implement authoritative readiness, a single production secret-input resolver, durable campaign controls, and checked-in preflight/query/job-status/live-smoke scripts.
- Staging — Provision Redis/secret containers, require authorised exact GCP source/version population and Google callback gates, dark-launch Identity, prove two pre-rollout tokens across an Argo-managed rollout, then execute independently approved OpenIddict switch, Auth0 rollback, and OpenIddict reapply checkpoints.
- Production preparation — Require a separate authorised production GCP source/version gate, dark-launch Identity without changing Web/API authentication, prove the two-token Argo-rollout/backup contract, establish exact 24-hour telemetry queries before BFF rollout, then move browsers to BFF cookies backed by Auth0.
- Migration and cutover — Execute and inspect distinct GitOps import/verify/rerun, canary/approve/batch/stop/status/resume/final/rerun, reconciliation, and readiness Jobs while Auth0 remains live; meet three authoritative thresholds; then atomically switch BFF authority and identity administration to OpenIddict.
- Fallback observation — Retain Auth0 runtime code, configuration, secrets, tenant, and GitOps provider flags as a tested kill switch for four timestamped reviews spanning at least 28 days.
- Sequenced cleanup — After the observation gate, use bounded (<15-path) Angular/core/event/seed slices, remove API Auth0/JWT runtime paths, preserve BSON, regenerate chart/schema/client output twice for idempotence, then separately promote/rollback/reapply staging, promote production, and remove obsolete GitOps refs.
- External cleanup and shutdown — Preserve final exports, classify every obsolete GCP version/Google callback/Auth0 tenant action, and require authorised administrators to apply those external decisions manually.
Locked Boundaries¶
- Do not point
signin.syrf.org.ukat OpenIddict. It remains the Auth0 custom domain. OpenIddict usesidentity.staging.syrf.org.ukandidentity.syrf.org.uk. - Add staging and production Identity Google redirect URIs without deleting the working Auth0 redirect URI until G4 has passed.
- Identity has one explicit public issuer per environment. Only known ingress proxy networks/addresses may supply forwarded headers; forwarded host/proto from arbitrary clients is forbidden.
- Campaign CLI and every Identity replica use the same DataProtection application name, encrypted Mongo-backed key-ring collection, and encryption certificate/key. Process-local keys are forbidden outside Development.
- S02 readiness must not depend on the shared ring before S03 creates it. S03 alone adds ring readiness and proves two tokens generated before redemption: one before and one after process/replica restart.
- BFF provider is explicit (
auth0oropeniddict); it is never inferred from a hostname. Session keys include provider, normalized issuer, and an immutable rollout generation. Every switch and rollback uses a fresh generation so old cookies fail closed. - When BFF is disabled, the combined authentication selector ignores every BFF cookie and selects JWT/API-key behavior.
- Do not remove Auth0 fallbacks before G4. GitOps
authProvider,BffAuth.Enabled, provider, authority, client, and session-generation values remain the operational kill switch throughout the 28-day observation window. - Post-G4 cleanup is intentionally unflagged: once the staged cleanup is promoted to production, Angular and API have a single BFF/OpenIddict runtime path and rollback is by reverting the cleanup release, not a dormant Auth0 feature flag.
- Production import, verify, readiness, campaign, status, stop, resume and reconcile commands use one resolver for mounted secrets/inherited descriptors. Canary members and durable run handles never appear in GitOps, argv, logs, diffs, or public evidence.
- Campaign stop is a durable Mongo control transition checked before every claim/send. Pod-local stop files are forbidden; resume uses a new durable control generation.
- Do not put secrets, private keys, raw exports, emails, stable user/Auth0/project/job/run identifiers, canary members, session IDs, nonces, tokens, secret-version identifiers, or sensitive source/export/secret paths in GitOps, argv, logs, diffs, or public evidence. Secret material stays in GCP Secret Manager; restricted inventories expose only aggregate hashes/counts publicly.
- Use GitOps only for Kubernetes mutations. Rollouts use reviewed values/nonce commits and Argo reconciliation; direct pod restart/delete/patch,
kubectl apply, andhelm installare forbidden. Read-only diagnostics/port-forwarding are permitted. - Every provider/release rollback and reapply is a separate approval, merge, Argo sync, and live checkpoint with a distinct Git revision and session generation; no command chains rollback and reapply.
- Staging/production secret references may be deployed only after an authorised operator reconciles the exact rendered GCP resource/version inventory to approved source owners and confirms enabled versions were populated outside Terraform/GitOps.
- Before G2, the production confidential Auth0 BFF client secret is transferred from that exact Auth0 application into one authorised enabled
syrf-auth0-bff-productionGCP version, andextra-secrets-productionmaps only itsclientSecretproperty to the API Secret ref. The value and version identifier never enter GitOps or public evidence. - Keep
ApplicationUser.Auth0UserId,MigrationLog.Auth0UserId, the Auth0 export parser, and retained exports as migration/audit data pending a separate retention decision. - Preserve the production MongoDB BSON field name
Auth0Idwhen renaming the C# domain property, including serializers used by AppServices,ApplicationService, controllers, command/query handlers, and tests. -
2442 tenant shutdown is manual-only. No plan or script may invoke an Auth0 deletion, disable, or cancellation API.¶
- Final external cleanup occurs only after the encrypted export and restricted classification. Each obsolete GCP Auth0 version is explicitly retained/disabled/destroyed, the Google Auth0 callback is removed while both Identity callbacks remain, and tenant disable/cancel is manual; automation is read-only.
- Every automated command resolves and asserts a physical
*/.worktrees/<name>,*/pr/<name>, or*/agents/<name>repository worktree root plus linked<git-common-dir>/worktrees/*metadata. The guard supports normal.gitand bare.barecommon directories and refuses/maineven when bare Git records it as a linked worktree.
Entry Condition¶
M005 planning may proceed from the current Auth0 production state. Execution starts with the Wave 1 application-readiness slices and may not skip directly to environment rollout, cleanup, or decommission.