Skip to content

Session teardown fires on every 403, so an authorization denial logs the operator out #217

Description

@linear

As of frontend 14dbb73 (#36), apiRequest clears the session and redirects to /login on any non-exempt 401 or 403. That conflates two different answers: "your session is dead" and "you may not do this thing". RoleChecker denials ("Operation not permitted"), inactive users, and the new creator-or-admin check on annotation deletes (#214, backend PR #49) are all healthy-session 403s — and each one now logs the operator out mid-task instead of showing an inline error.

Correction (2026-07-22): an earlier version of this issue claimed the 403 teardown branch was "necessary today" because FastAPI's auto-error HTTPBearer surfaces a missing or malformed Authorization header as 403. Verified empirically against the pinned stack (FastAPI 0.139.0, per #48): missing and malformed headers both return 401, not 403 — the 403-on-missing-credentials behaviour belongs to older FastAPI versions. On our stack the 403 branch protects nothing; it only causes the spurious logouts.

Evidence: frontend/src/lib/api.ts:86-96 (401 or 403 → clearSession() + goto('/login')); backend/app/api/auth.py (RoleChecker → 403 with a live session); #214's 403 on the annotations DELETE; probe against the dev backend: no Authorization header → 401, malformed header → 401 on the auto-error bearer.

Fix (a coordinated pair; landing order immaterial on the pinned stack, since every missing/invalid-credential path already returns 401):

  1. Frontend — the load-bearing half (PR Wiring #38): restrict the teardown branch to 401; 403 falls through to a plain catchable error that components display inline (the annotation panel already renders these).
  2. Backend — hardening (PR Authentication & secrets (backend) #50): replace the auto-error bearer with an optional bearer plus explicit HTTPException(401, "Not authenticated"), so the status is chosen by our code rather than a framework default that has varied across FastAPI versions.

Acceptance. An expired, invalid, or missing token still redirects to login from any screen; a forbidden action (role denial, creator-or-admin denial) shows an inline error with the session intact; backend PR #49 (#214) unblocks.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions