bdbb7ae196
JWT access tokens freeze role/identity at login (access 1h, refresh 7d) and validated tokens are cached for 30s. The Bearer and cookie auth paths trusted claims.role and never re-checked the account, so demoting an admin, or disabling/deleting an account, did not revoke access until the token expired. The app-password path already re-read role/active from the DB; only the JWT/cookie path had the gap. Re-validate the caller against the live user record on the token path via the already-cached get_user_flags (role / is_external / active), bounded by USER_FLAGS_CACHE_TTL and invalidated eagerly on set_user_active / change_user_role / delete_user_admin: - middleware/user.rs: new resolve_live_role helper (+ pure decide_live_role core) — returns the *current* role, rejects deleted (NotFound) and deactivated accounts, and fails open on transient lookup errors (mirrors require_internal_user). Login/refresh remain the canonical active gate. - middleware/auth.rs: auth_middleware (Bearer + cookie) now populates CurrentUser with the live role and rejects revoked accounts (Bearer -> 401 AccountInactive; cookie -> fall through to 401/login redirect). require_admin emits an audit line on denial. - middleware/admin.rs: require_admin / require_authenticated re-check the live record, return the live role, and audit admin denials. Downstream admin gates (dedup_handler, subject_group_handler, OCS) inherit the live role automatically via CurrentUser / require_authenticated. Tests: decide_live_role policy (active / demoted / deactivated / deleted / transient fail-open) and AccountInactive -> 401. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TAzLEQDaLak3dnrEN3YT35