---
title: "Survive an expired session · Agent Wranglers"
url: https://agentwranglers.se/playbook/app-ui/sessions-and-permissions/session-expiry
id: APP-48
level: Required
applies: accounts
risk: data
updated: 2026-10-22
build: a2a6bdfed830
tokens: 918
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Survive an expired session

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Sessions and permissions](https://agentwranglers.se/playbook/app-ui/sessions-and-permissions.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: APP-48
- Level: Required
- Chapter: [Sessions and permissions](https://agentwranglers.se/playbook/app-ui/sessions-and-permissions.md)
- Rule: When a session expires, keep the screen and the unsaved work. Let the person sign in again in place, then repeat the request that failed.
- Check: A browser test fills a form, deletes the session cookie and submits. A sign-in prompt appears, and after signing in the form is saved with the values typed before.
- Risk: Data leaked or lost
- Applies when: The project has user accounts.
- How: For script requests, the server answers 401 with problem details, never a redirect to an HTML sign-in page. The client keeps its state, opens sign-in in a dialog or a new tab, and retries the request once sign-in succeeds. Warn before a timed sign-out and offer more time, as [time limits](https://agentwranglers.se/playbook/accessibility/forms-changes-and-time/time-limits.md) requires. The idle and total session limits are in [lock down session cookies](https://agentwranglers.se/playbook/application-security/authentication-and-sessions/session-cookies.md).

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### TypeScript example

```ts
export async function apiFetch(input: string, init?: RequestInit): Promise<Response> {
  const response = await fetch(input, init);
  if (response.status !== 401) return response;
  await signInAgain();
  return fetch(input, init);
}
```

### Python example

```python
@app.errorhandler(SessionExpired)
def session_expired(_error):
    wants_page = request.accept_mimetypes.best == "text/html" and "HX-Request" not in request.headers
    if wants_page:
        return redirect(url_for("sign_in", next=request.path))
    return problem(401, "session-expired", title="Please sign in again")
```

## Sources

- [WCAG 2.2 criterion 2.2.1 Timing Adjustable](https://www.w3.org/TR/WCAG22/#timing-adjustable)
- [WCAG 2.2 criterion 2.2.5 Re-authenticating](https://www.w3.org/TR/WCAG22/#re-authenticating)
- [RFC 9457 Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457)

## Related rules

- AXS-36 [Give people enough time](https://agentwranglers.se/playbook/accessibility/forms-changes-and-time/time-limits.md) in Accessibility
- APS-16 [Lock down session cookies](https://agentwranglers.se/playbook/application-security/authentication-and-sessions/session-cookies.md) in Application security

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/app-ui/sessions-and-permissions/session-expiry">Agent Wranglers web app interface playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Let the server say what each user may do](https://agentwranglers.se/playbook/app-ui/sessions-and-permissions/capabilities-from-server.md)
- Next: [Sign out every open tab together](https://agentwranglers.se/playbook/app-ui/sessions-and-permissions/sign-out-all-tabs.md)
- [Sessions and permissions](https://agentwranglers.se/playbook/app-ui/sessions-and-permissions.md)
