When a session expires mid-transaction, the partially-completed work must survive the re-authentication round trip -- the server-side draft keyed to the user identity, or encrypted in the re-auth payload, so the user returns to the same step with the same data
2.2.5 Re-authenticating
In Plain Language
2.2.5 Re-authenticating (Level AAA) says that when an authenticated session expires mid-activity, the user can continue after re-authenticating without loss of data[1]. The partially-completed work -- form fields, multi-step wizard position, comment draft, shopping cart, document edits -- has to survive the auth round trip.
Mechanism: the application persists in-progress state somewhere that outlives the session (server-side draft keyed to the user, encrypted payload round-tripped through the re-auth page, or client-side storage) and rehydrates it after the login succeeds. The spec's sufficient techniques name exactly two paths: server-side draft storage (G105) and encrypted hidden-field encoding (G181)[1].
Why It Matters
- Users with cognitive and learning disabilities work through multi-step forms at a pace the session timer did not account for. When the 30-minute idle timer fires on step 14 of a 20-step benefits application, a re-auth flow that drops the user at step 1 of an empty form is not a minor inconvenience -- it is a hard stop on the task.
- Screen-reader users traverse forms linearly and verify each field against its accessible name before committing, so a session that times out during composition costs more re-entry time than it would for a sighted mouse user.
- Switch users, eye-tracker users, and users typing with head pointers operate at input rates measured in characters per minute, not per second. A timeout that discards input penalises exactly the users 2.2.5 exists to protect.
- 2.2.5 sits next to 2.2.1 Timing Adjustable: 2.2.1 gives the user a way to extend or disable the timer, 2.2.5 is the backstop for when the timer fires anyway. Shipping one without the other leaves a data-loss gap.
Examples
Session expired during form entry:
1. User fills steps 1-3 of a 5-step form
2. Session times out -- server saves draft
3. User re-authenticates
4. Application restores form at step 3
✔ All data preserved across re-authentication
<!-- Periodic server-side draft save, keyed to user id -->
<script>
const form = document.getElementById('app-form');
setInterval(() => {
const body = new FormData(form);
body.append('draft_id', form.dataset.draftId);
fetch('/api/drafts', { method: 'POST', body, credentials: 'same-origin' });
}, 30000);
</script>
<!-- On re-auth success, server looks up the draft by
(user_id, draft_id) and redirects back to the form
with the saved state rehydrated -->
Re-login form carries the encrypted return state:
<input type="hidden" name="return_to" value="/wizard/step-3">
<input type="hidden" name="state" value="enc:AES-GCM:...">
✔ After login, server decrypts the state and rehydrates the wizard
<!-- Re-auth page carries the pending state as an
encrypted, integrity-protected blob (G181) -->
<form action="/login" method="POST">
<input type="hidden" name="return_to" value="/wizard/step-3">
<input type="hidden" name="state"
value="enc:AES-GCM:9f2a...e4b1">
<label for="username">Username</label>
<input type="text" id="username" name="username" autocomplete="username">
<label for="password">Password</label>
<input type="password" id="password" name="password" autocomplete="current-password">
<button type="submit">Sign in</button>
</form>
Session expired -- all form data lost:
1. User fills steps 1-3 of a 5-step form
2. Session times out
3. User re-authenticates
4. Redirected to home page -- form data gone
✘ User must restart the entire form from scratch
Error page on session expiry:
<h1>Session Expired</h1>
<p>Your session has timed out.</p>
<a href="/login">Log in again</a>
✘ No draft saved, no return URL -- all user data is permanently lost
How to Fix It
- Persist drafts server-side, keyed to user identity plus a draft id. On a periodic interval (every 20-30 seconds during active editing) and on every meaningful state change (step transition, field blur on a long textarea), POST the current state to a drafts endpoint. Key the record by
(user_id, draft_id)so the re-auth handshake can look it up without a live session. This is the W3C sufficient technique G105[1]. - Or round-trip the state through the re-auth page as an encrypted blob. Serialize the pending state, encrypt with an integrity-protected construction (AES-GCM, not raw AES-CBC), drop it into a hidden field on the login form, and decrypt it on successful authentication. This is W3C sufficient technique G181 and is the fallback when server-side draft storage is not available[1].
- Detect impending session expiry and prompt re-auth in place. At roughly 90% of the inactivity timeout, open a modal that re-authenticates against the same origin (fetch to
/auth/refresh, or a silent OAuth refresh) without unmounting the underlying page. The DOM state -- form fields, scroll position, open accordions -- stays live because the page never navigates. Pair this with 2.2.1 Timing Adjustable so the warning itself offers an extend-session action. - Use client-side storage as a belt-and-braces fallback. IndexedDB with a periodic save (or
sessionStoragefor short flows) catches the cases where the network save failed before the timeout. Restore from client storage on page load when a matching draft id is present in the URL. Client storage is not a substitute for server-side drafts -- it does not survive a device change -- but it closes the tab-crash gap. - Exercise the full timeout-and-recovery cycle in tests. Force the session to expire (clear the session cookie, or wait out the timer on a shortened test config), re-authenticate, and assert that every field -- including file uploads, radio selections,
contenteditableregions, and scroll position -- is restored. A manual walkthrough on the longest form in the product catches the regressions automated tests miss.
References
- [1] W3C (2023). Understanding Success Criterion 2.2.5: Re-authenticating. W3C, Accessed 2026-04-07. https://www.w3.org/WAI/WCAG22/Understanding/re-authenticating.html ↩ ↩ ↩ ↩