fix(admin): revoke refresh-tokens on claim-feeding mutations (BUNYIP-144) #175
No reviewers
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
psa-systems/bunyip!175
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/bunyip-144-revoke-rt-on-claim-mutations"
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?
Extends the BUNYIP-137 revoke-on-role-change pattern to every admin
handler that mutates a field feeding
has_member_access. Without this,the dashboard's per-app gate (Mokosh / Drillmark / Lets Chat tiles)
keeps rendering the pre-grant state for an unbounded window because the
user's still-valid refresh token mints access tokens with stale claims
on every rotation - and the SPA reads
CurrentUserfrom those cachedclaims, not from a live DB join.
Hit in the field: brendon@netcal.com (2026-06-19) was promoted to
lifetime member but his Mokosh tile stayed greyed out until a manual
sign-out + sign-in.
Helper
revoke_user_sessions(pool, user_id)wraps the existingTokenRepository::revoke_all_user_refresh_tokenscall so each handlercollapses to a one-liner and the audit-log metadata can carry
sessions_revoked: trueconsistently.Wired into:
update_user_status(both deactivate AND reactivate branches; thelatter is belt-and-braces against a future regression that would let
a stale token leak past restore).
grant_membership(sets lifetime_member=true + subscription=active).revoke_membership(privilege-DOWNGRADE; the strongest securityargument of any handler in this set - without it the user keeps
admin-or-member claims for the full 30-day refresh TTL).
grant_lifetime_membership(the brendon@netcal.com fix).revoke_lifetime_membership(privilege-downgrade, same posture).Not touched:
update_user_rolealready had it (BUNYIP-137); pattern reused.change_password(domain service) already revokes at line 864 ofcrates/bunyip-domain/src/services/auth.rs; password-reset confirmation
flows through that path.
admin_reset_password(only sends the reset email; the actualpassword change happens through the user-initiated confirmation,
which is already covered).
delete_user(soft_delete sets deleted_at; the auth middleware dropstokens whose user row has deleted_at IS NOT NULL, so revocation here
is redundant; file a follow-up if a regression ever changes that).
a verified TOTP enrolment, not to membership state; revoking them on
every grant would log the user out of their browser device too, which
is the opposite of what we want.
just check-containergreen (fmt + clippy -D warnings + workspacelib tests).
#BUNYIP-144
#BUNYIP-137
Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com