Skip to content

[2.x] feat: change logout from GET to POST#4448

Merged
imorland merged 3 commits into2.xfrom
im/post-logout
Mar 14, 2026
Merged

[2.x] feat: change logout from GET to POST#4448
imorland merged 3 commits into2.xfrom
im/post-logout

Conversation

@imorland
Copy link
Copy Markdown
Member

Summary

  • GET /logout now only shows a no-JS confirmation page (LogOutViewController) — it never performs a logout
  • POST /logout is the new action endpoint (LogOutController) — reads the CSRF token from the request body and performs the logout
  • Session.ts now submits a hidden form via POST instead of navigating via window.location.href
  • The no-JS confirmation page (log-out.blade.php) now renders a <form method="POST"> with a hidden token field instead of an <a> link

Why:

  • GET requests should be side-effect free; session destruction is a state mutation
  • The CSRF token was previously in the query string, leaking to server logs, browser history, and Referer headers
  • Prefetchers / link crawlers can follow GET links without user intent

Closes #4427

Test plan

  • 9 new integration tests in LogoutTest.php covering: guest POST redirects, wrong/missing token falls back to confirmation page, valid token logs out and deletes the access token, safe return URL is honoured, external return URL is blocked, GET shows confirmation page with POST form, GET does not destroy any tokens
  • Manual: click Log Out in the UI, verify the session is destroyed and you're redirected
  • Manual: visit /logout directly (no JS), verify the confirmation page shows a button that works

🤖 Generated with Claude Code

imorland and others added 2 commits March 14, 2026 23:26
The /logout route was a GET, which is semantically incorrect for a
state-mutating operation (session destruction). This also meant the CSRF
token was carried in the query string, leaking it to server logs,
browser history and Referer headers.

Changes:
- GET /logout (new route name: logoutPage) shows a no-JS confirmation
  page only — it no longer performs any logout action
- POST /logout (route name: logout) validates the CSRF token from the
  request body and performs the actual logout
- LogOutViewController handles the GET confirmation page
- LogOutController now handles POST only and reads the token from the
  parsed body instead of the query string
- Session.ts submits a hidden form via POST instead of navigating via
  window.location.href
- log-out.blade.php uses a POST form with a hidden token field instead
  of a plain link

Closes #4427

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imorland imorland requested a review from a team as a code owner March 14, 2026 23:26
@imorland imorland added this to the 2.0.0-beta.8 milestone Mar 14, 2026
The CSRF middleware checks for `csrfToken` in the body or `X-CSRF-Token`
header. The form and Session.ts were sending `token`, causing a 400
"inactive for too long" error on logout.

- Rename the hidden form field from `token` to `csrfToken` (blade view)
- Rename the JS field from `token` to `csrfToken` (Session.ts)
- Remove the now-redundant manual token check from LogOutController —
  the CSRF middleware already validates the token before the controller runs
- Update tests accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
imorland added a commit to flarum/docs that referenced this pull request Mar 14, 2026
…#4448)

The /logout route is now a POST action. The GET route is renamed to
logoutPage and only shows a no-JS confirmation page. Extension authors
generating logout URLs or submitting logout requests directly need to
update their code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imorland
Copy link
Copy Markdown
Member Author

Docs: flarum/docs#510

imorland added a commit to flarum/docs that referenced this pull request Mar 14, 2026
…#4448) (#510)

The /logout route is now a POST action. The GET route is renamed to
logoutPage and only shows a no-JS confirmation page. Extension authors
generating logout URLs or submitting logout requests directly need to
update their code.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@imorland imorland changed the title feat: change logout from GET to POST [2.x] feat: change logout from GET to POST Mar 14, 2026
@imorland imorland merged commit d3022b7 into 2.x Mar 14, 2026
27 checks passed
@imorland imorland deleted the im/post-logout branch March 14, 2026 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[2.0] Change HTTP Request Method for Logout Route

2 participants