#4557·romm

[Bug] Browser Back after an OIDC login re-submits the spent state; auth_openid answers 500 (MismatchingStateError) instead of restarting login

Author: f0rthelulzCreated Sep 16, 2026Updated Sep 16, 2026

AI assistance disclosure

Per CONTRIBUTING.md: this issue was written by Claude Code (Anthropic) from measurements it took under my direction on my own RomM instance; I reviewed the report and the evidence. If replies are written with AI assistance I will say so.

RomM version

5.2.0. backend/endpoints/auth.py line 290 (auth_openid: token = await oauth.openid.authorize_access_token(request)) has no handler for authlib's MismatchingStateError; unchanged on master at 14fc8d9.

Describe the bug

After a successful OIDC login, one press of the browser's Back button on the home page re-enters the provider's authorization page, which still carries the original state. The provider (Authelia here) re-authenticates and redirects to /api/oauth/openid with a new code and the old, already-consumed state. RomM raises MismatchingStateError and the user is left on a bare Internal Server Error page instead of being sent back to login.

A second way in: the v2 UI's gamepad navigation treats Standard button 1 (B, ○ on a DualShock 4) as back, so a pad player meets the same 500 on their first ○ at the home page.

To Reproduce

  1. Sign in with OIDC (Authelia, with 2FA). Land on /.
  2. Press Back once. The history entry is https://auth.example/?rd=…/api/oidc/authorization?…&state=<original>.
  3. Complete the provider's prompt. It redirects to /api/oauth/openid?code=<new>&state=<original>.
  4. RomM answers 500. Log:
ERROR: [RomM][httptools_impl][2026-09-16 12:01:18] Exception in ASGI application
  File "/backend/endpoints/auth.py", line 290, in auth_openid
    token = await oauth.openid.authorize_access_token(request)
    raise MismatchingStateError()
authlib.integrations.base_client.errors.MismatchingStateError: mismatching_state: CSRF Warning! State not equal in request and response.
GET /api/oauth/openid?code=…&state=wrkRHIxoasz9gaxLJljVxPrBFvNO28 500

The same state had been accepted (307) four minutes earlier for the real login.

Expected behavior

authlib's rejection of a stale state is correct; the response is not. Suggestion, as a suggestion: catch MismatchingStateError (or authlib.integrations.base_client.errors.OAuthError) around line 290 and redirect to /login so a fresh flow starts, rather than a 500. If the user already has a valid session cookie, redirecting to / would be even kinder.

Desktop

  • OS: macOS 27.0
  • Browser: Chromium 149.0.7827.55; first seen with a gamepad in the v2 UI, reproduced with the plain Back button
  • Provider: Authelia (OIDC), 2FA on