feat(auth): session hardening - panel, role-change revoke, admin TTL/idle #165
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/bunyip-137-session-hardening"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Implements BUNYIP-137 single sign-on hardening across three self-contained areas. No new tables, no migrations.
1. Active-sessions panel
GET /v1/users/me/sessionsnow returns acurrentflag per session, set by hashing the caller's presentedrefresh_tokencookie and matching it to the stored row. The storedtoken_hashis never returned.POST /v1/users/me/sessions/revoke-othersrevokes every active session for the caller except the current one. Backed by a newTokenRepository::revoke_other_user_refresh_tokens(scoped to the legacyrefresh_tokenstable).DELETE /v1/users/me/sessions/{id}, with its existing caller-ownership guard) is reused unchanged./settings: each device with IP and a relative "last active" time, a "This device" badge on the current session, a per-row Revoke button for non-current sessions, and a "Log out all other devices" action. Rotated cookies are relayed via the existingredirect_cookiespath.2. Revoke sessions on role change
update_user_rolerevokes the target user's sessions (legacy + OIDC families, via the existingrevoke_all_user_refresh_tokens) only when the role actually changes. A demoted admin can no longer make admin calls once their access token is revoked or expires. The role-change audit entry recordssessions_revoked.3. Admin session lifetime + idle timeout
bunyip-domain(refresh_absolute_ttl,refresh_idle_ttl), not inline literals. The idle decision is a pure function (session_idle_expired) with unit tests.Tests
Four pure unit tests cover the role-based TTL/idle policy (admin vs subscriber absolute TTL, admin-only idle window, over-idle admin rejected, subscriber never idle-expires). The cross-user revoke guard and revoke-others keep-current behavior are DB-integration paths (no database in the
just checklib-test harness) and are enforced in the handler/repository code.Verification
just check-container(fmt + clippy-D warnings+ build + workspace lib tests) passes clean; 191 domain + 19 api + 9 oci + 9 oidc tests green.Note on the spec
The issue proposed new
/v1/auth/sessionsendpoints. During implementation I found the API already exposes/v1/users/me/sessions(list + single-revoke), so I extended that surface (added thecurrentflag and the revoke-others endpoint) instead of creating a duplicate API. Deferred follow-up: remember-this-device / TOTP-skip is tracked in BUNYIP-138.🤖 Generated with Claude Code