# Session does not expire unexpectedly; inactivity warning present with time to extend

- **Pattern:** `ab-001609` (`gov-section-508.forms-interactive.session-timeout`)
- **Severity:** info
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001609
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001609)

## Why it matters

Users with cognitive disabilities, motor impairments, or those using assistive technology work more slowly and may legitimately need longer to complete tasks. A session that expires silently and discards form data—a grant application, benefits form, or tax filing—causes real harm beyond mere inconvenience. WCAG 2.2 SC 2.2.1 (Level A) requires that users be warned before a time limit expires and given an opportunity to extend it without data loss. SC 2.2.2 (Level A) targets automatic page updates that move content without user control. Section 508 2018 Refresh 503.3.5 incorporates timing control requirements. Silent session expiry during form-heavy government workflows is a common Section 508 complaint category.

## Severity rationale

Info because session timeout issues are scoped to authenticated flows and do not block access to public content, but they cause significant data-loss harm to users working slowly on form-heavy tasks.

## Remediation

Implement a session warning dialog that appears at least 60 seconds before expiration and offers an extend option without requiring re-authentication. In a client component wrapping authenticated pages:
```tsx
const SESSION_DURATION_MS = 15 * 60 * 1000; // 15 minutes
const WARNING_BEFORE_MS = 60 * 1000; // 1 minute warning

useEffect(() => {
  const warningTimer = setTimeout(() => {
    setShowWarning(true); // Show dialog
  }, SESSION_DURATION_MS - WARNING_BEFORE_MS);

  return () => clearTimeout(warningTimer);
}, [lastActivity]);

{showWarning && (
  <div role="alertdialog" aria-modal="true" aria-labelledby="timeout-title">
    <h2 id="timeout-title">Your session is about to expire</h2>
    <p>You will be logged out in 60 seconds. Any unsaved changes will be lost.</p>
    <button onClick={extendSession}>Stay logged in</button>
    <button onClick={logout}>Log out now</button>
  </div>
)}
```
Use `role="alertdialog"` (not `role="dialog"`) so screen readers immediately announce the warning without waiting for the user to navigate to it.

## Detection

- **ID:** `session-timeout`
- **Severity:** `info`
- **What to look for:** Count all relevant instances and enumerate each. Check whether the application has user authentication. If so, examine the code for session timeout logic. Look for warnings or alerts before session expiration. Check whether users have an opportunity to extend their session (button to continue, dialog with countdown).
- **Pass criteria:** If the app has authentication, sessions do not expire silently. Users receive a warning at least 20 seconds before expiration and can extend the session without losing data.
- **Fail criteria:** Sessions expire without warning, or users have no opportunity to extend them.
- **Skip (N/A) when:** No user authentication or session management exists.
- **Detail on fail:** Example: `"User sessions time out after 15 minutes of inactivity. No warning is displayed. Users lose unsaved form data when the session expires."`
- **Remediation:** Implement a session warning:
  ```tsx
  useEffect(() => {
    const sessionTimeout = 15 * 60 * 1000; // 15 minutes
    const warningTime = 1 * 60 * 1000; // 1 minute before timeout

    const timer = setTimeout(() => {
      // Show warning dialog
      setShowWarning(true);
    }, sessionTimeout - warningTime);

    return () => clearTimeout(timer);
  }, []);
  ```

## External references

- wcag 2.2.1
- wcag 2.2.2
- section-508 503.3.5

Taxons: accessibility

HTML version: https://auditbuffet.com/patterns/ab-001609
