Make the uncertain state explicit
Use action states that distinguish a failed identity check from a denied business action or an interrupted request:
ready → pending → session_expired → reconfirmation_required → pending
├────────────→ already_processed
└────────────→ denied
pending → accepted | denied | unknown_outcome
MDN's 401 response reference describes an authentication challenge. It does not say whether the original business action ran. The API needs a documented way to inspect the record or a request identifier after authentication is restored.
Preserve intent, not an automatic replay
Retain the displayed decision, record identity, and record version long enough to explain what happened. Do not make those local values permission to send another approval. After reauthentication:
- Fetch the current record and server-reported outcome.
- If the server says the action already completed, show that result and stop.
- If the record is no longer eligible or the current authorization denies the action, show that result and stop.
- If it is still eligible, show the current facts and ask the person to confirm again.
- Submit a new request only after that explicit confirmation and under the server's current authorization and version rules.
React's useOptimistic
can render a temporary pending state during an Action. It cannot authenticate a
session, determine whether a previous request committed, or authorize the next
one.
Test the decision path before the component
The P99 model checks that session expiry retains intent without accepting it, reauthentication blocks a new send until reconfirmation, a processed outcome cannot be reconfirmed, and denial remains distinct from an unknown outcome. The model is not an authentication-provider, idempotency-key, browser, or accessibility test.
Leave trusted work to the server
The backend owns authentication, authorization, anti-replay rules, durable approval evidence, request identity, and the final decision record. A disabled button, a session-expiry message, or a React state transition cannot supply any of them. Stop before shipping if reauthentication automatically repeats a consequential action or the product cannot determine what happened to the first request.