fix(GRO-2234): transparent re-mint on 401 for portal Book New submit #55

Merged
Flea Flicker merged 2 commits from flea-flicker/gro-2234-portal-waitlist-remint-on-401 into dev 2026-06-08 19:13:03 +00:00
Member

GRO-2234 — Portal Book New: transparent re-mint on waitlist 401

Problem

A deliberately-paced Book New wizard (~1–2 min) could outlive the portal impersonation session, so the final POST /api/portal/waitlist returned 401 {"error":"Unauthorized"} and the UI showed "Failed to book appointment. Please try again." A freshly-minted session with the same payload returned 201.

Fix — one-shot re-mint + retry (defense-in-depth)

  • src/portal/sections/Appointments.tsx
    • remintPortalSession() — POSTs /api/portal/session-from-auth (credentials: include) and returns a fresh sessionId, or null when there is no Better Auth session (staff/dev impersonation paths).
    • handleConfirmBooking() — submits the waitlist via submitWaitlist(id); on a 401, re-mints once (the customer's Better Auth cookie is still valid) and retries the submit with the fresh X-Impersonation-Session-Id. Falls through to the existing error UI if re-mint fails.

Companion API change

Pairs with groombook/api PR #183 (GRO-2234) which adds bounded sliding expiration so SSO portal sessions rarely lapse during active use. This web change is the deterministic user-facing recovery if a session does lapse.

Tests

src/__tests__/Appointments.test.tsx — new case: first waitlist POST → 401, then session-from-auth → fresh id, then retried waitlist POST → success. Asserts exactly one re-mint and the header sequence ["stale-session-id", "fresh-session-id"], and that no error is surfaced. Full suite green (66 tests); typecheck + lint clean.

UAT_PLAYBOOK

Updated §5.12e — added TC-WEB-5.12.25 (slow-wizard submit succeeds; documents the re-mint+retry network sequence).

cc @cpfarhood

## GRO-2234 — Portal Book New: transparent re-mint on waitlist 401 ### Problem A deliberately-paced Book New wizard (~1–2 min) could outlive the portal impersonation session, so the final `POST /api/portal/waitlist` returned `401 {"error":"Unauthorized"}` and the UI showed **"Failed to book appointment. Please try again."** A freshly-minted session with the same payload returned 201. ### Fix — one-shot re-mint + retry (defense-in-depth) - **`src/portal/sections/Appointments.tsx`** - `remintPortalSession()` — POSTs `/api/portal/session-from-auth` (`credentials: include`) and returns a fresh `sessionId`, or `null` when there is no Better Auth session (staff/dev impersonation paths). - `handleConfirmBooking()` — submits the waitlist via `submitWaitlist(id)`; on a `401`, re-mints once (the customer's Better Auth cookie is still valid) and retries the submit with the fresh `X-Impersonation-Session-Id`. Falls through to the existing error UI if re-mint fails. ### Companion API change Pairs with **groombook/api PR #183 (GRO-2234)** which adds bounded sliding expiration so SSO portal sessions rarely lapse during active use. This web change is the deterministic user-facing recovery if a session does lapse. ### Tests `src/__tests__/Appointments.test.tsx` — new case: first waitlist POST → `401`, then `session-from-auth` → fresh id, then retried waitlist POST → success. Asserts exactly one re-mint and the header sequence `["stale-session-id", "fresh-session-id"]`, and that no error is surfaced. Full suite green (66 tests); typecheck + lint clean. ### UAT_PLAYBOOK Updated **§5.12e** — added TC-WEB-5.12.25 (slow-wizard submit succeeds; documents the re-mint+retry network sequence). cc @cpfarhood
Flea Flicker added 1 commit 2026-06-08 18:55:14 +00:00
fix(GRO-2234): transparent re-mint on 401 for portal Book New submit
CI / Test (pull_request) Failing after 14m28s
CI / Lint & Typecheck (pull_request) Failing after 14m29s
CI / Build & Push Docker Image (pull_request) Has been skipped
915a310e0a
A deliberately-paced Book New wizard could outlive the portal impersonation
session, so the final POST /api/portal/waitlist returned 401 and the UI showed
"Failed to book appointment. Please try again."

BookingFlow now retries once on a 401: it re-mints a fresh portal session via
POST /api/portal/session-from-auth (the customer's Better Auth cookie is still
valid) and resubmits the waitlist request with the new
X-Impersonation-Session-Id. Falls through to the existing error if no Better
Auth session is available (staff/dev impersonation paths).

- Appointments.tsx: remintPortalSession() helper; handleConfirmBooking submits
  via submitWaitlist(id) and retries once after a 401 re-mint.
- Test: first waitlist POST 401 -> re-mint -> retry with fresh id -> success;
  asserts exactly one re-mint and the header sequence.
- UAT_PLAYBOOK.md 5.12e: TC-WEB-5.12.25 slow-wizard submit succeeds.

Companion to groombook/api GRO-2234 (bounded sliding expiration).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Flea Flicker added 1 commit 2026-06-08 19:11:27 +00:00
ci: re-trigger checks (transient runner failure)
CI / Test (pull_request) Successful in 25s
CI / Lint & Typecheck (pull_request) Successful in 27s
CI / Build & Push Docker Image (pull_request) Successful in 38s
0766332712
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Flea Flicker merged commit 1ceac35437 into dev 2026-06-08 19:13:03 +00:00
Sign in to join this conversation.