Skip to content

Phase 05 Plan S09: Staging Switch and Rollback Rehearsal Summary

Ordinary staging was switched to the BFF with native Identity, the live matrix passed on OpenIddict, and the rollback was rehearsed and passed. After S09, staging runs the BFF on Auth0 until S27 reapplies OpenIddict.

Timeline

When (UTC) Event Revision
Before 2026-10-04 Staging users imported from Auth0: 4 imported/matched, no emails sent camaradesuk/cluster-gitops#1537, #1538, #1539
2026-10-04 04:14:43 Switch: Web and API to the BFF plus native Identity, generation s09-staging-openiddict-1, same-origin /api (#1528), 2 API replicas, Swagger on the syrf-swagger PKCE client camaradesuk/cluster-gitops#1529
2026-10-05 / 2026-10-07 Task 2 live matrix on OpenIddict: extended rows 10-05, base rows 10-07 evidence files below
2026-10-06 Chris redefines Task 3 as option B
2026-10-07 04:31:00 Rollback (option B): BFF stays enabled, provider auth0, generation s09-staging-auth0-rollback-2. Rollout to 2/2 ready in 3 m 18 s camaradesuk/cluster-gitops#1530
2026-10-07 Task 3 live run on the BFF with Auth0 evidence file below

Task 2: live matrix on OpenIddict (passed)

Evidence (redaction-checked, mode 0600, git-ignored): .superpowers/sdd/auth-s30-2026-09-25/ -> s09-task2-evidence-2026-10-07.json and s09-task2-extended-evidence-2026-10-05.json.

  • Base rows: password sign-in, /api/auth/me, admin/account, protected API, SignalR reconnect, refresh/logout, emailed reset, two replicas sharing one session (2/2), Swagger PKCE without a client secret, and claims.
  • Extended rows: optional MFA (authenticator and recovery codes, including that a recovery code is single-use), passkeys (add, sign in, remove), and Google unlink after an emailed step-up.
  • Google sign-in is operator-attested by Chris, because the run host is headless.
  • Old-cookie rejection was not part of Task 2 (old_cookies_unauthorized_checked: 0); it belongs to Task 3.

Task 3: rollback rehearsal, option B (passed)

What changed. The plan said to restore direct Auth0 with the BFF disabled. On 2026-10-06 Chris changed it: the BFF stays enabled and its provider swaps OpenIddict to Auth0. That is the same shape as the production S13 rollback and the S11 baseline, so the rehearsal exercises the path production would take.

GitOps change (#1530). Provider auth0, authority https://signin.syrf.org.uk, a new Auth0 Regular Web App "SyRF staging BFF", its secret in GCP Secret Manager syrf-auth0-bff-staging through ExternalSecret auth0-bff, identityProvider: auth0, and Swagger kept on OpenIddict. Evidence: s09-task3-option-b-evidence-2026-10-07.json.

Live run, 2026-10-07 (result: pass):

  • The retained OpenIddict-generation cookie was refused (401) on both replicas.
  • A fresh Auth0 sign-in through the BFF was accepted on both replicas.
  • /me, protected API, SignalR and refresh/logout passed.
  • Auth0 IdP logout was proven: the next sign-in shows Universal Login.
  • Not run, by design: the emailed reset row and the admin row, because the Auth0 tenant is shared with production. The evidence records both under not_run.
  • Google is operator-attested. Chris's manual checks passed: Auth0 password, Google, the account page, a project, the admin page, and staying signed out after sign-out.

Recovery time was not measured separately. The only figure is the 3 m 18 s rollout to 2/2 ready.

Bugs found and fixed

PR Found in Fix
#4026 Task 2 Passkey Register failed silently on an implicit [Required] binding; also PasswordRetry; a reflection guard test now pins it
#4030 Task 2 Post-sign-in redirects: an authenticated Identity root goes to the web app, reset keeps returnUrl, a Google link returns to ExternalLogins
#4042 Task 2 Default-handler form actions posted to ?handler= after a failed handler post (the 2FA page)
#4047 Task 2 ID-4: the account is kept after a committed Investigator claim on a first Google sign-in
#4098 Task 3 Auth0 logout through /oidc/logout; BFF/direct-JWT name overwrite; a refused sign-in shown like direct Auth0; provider-aware live harness
#4105 Task 3 Per-flow PKCE cookies, so silent and interactive flows no longer clobber each other; /api/auth/callback/{appPath} forwards Auth0 Action links such as /auth/confirmation-email-sent
#4106 Task 3 End the Auth0 session on the Action email-sent pages through /v2/logout in a hidden iframe

Related improvements shipped during S09: silent sign-in #4097 (bffSilentSignIn) and flicker-free hidden-iframe silent sign-in with sliding sessions #4104 (bffSilentSignInFrame, bffSlidingSession, Identity identitySilentSignInFrame). They are enabled on staging through camaradesuk/cluster-gitops#1602 and #1610.

Production consequences

  • The production rollback path at S11/S13 needs a new Auth0 application and secret. The checklist is in S11-PLAN.
  • The S13 gate (G3) also requires account-portal slices 1-3 (plan). S10-S12 proceed in parallel and are not gated by them.

Next

Update 2026-10-07: S27 is done (S27-SUMMARY). Staging runs the BFF on OpenIddict again, and both retained generations were refused. The list below is kept as written at S09.

  • S27 (camaradesuk/cluster-gitops#1531): reapply the BFF plus native Identity, generation s27-staging-openiddict-3. It must refuse both retained generations, so a session cookie from each of s09-staging-openiddict-1 and s09-staging-auth0-rollback-2 must be retained for it. It needs Chris's go.
  • Delete the Auth0 staging test user.
  • Decide whether to keep the "SyRF staging BFF" Auth0 application as a standing rollback path.