feat(audit): emit auth_refresh_reuse_detected on refresh-token replay #109
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!109
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/audit-refresh-reuse-event"
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?
Closes BUNYIP-88.
The refresh-token reuse detection branch in
crates/bunyip-oidc/src/services/oidc_provider.rscorrectly revokes the whole token family on replay (refresh_token_families.revoke_reason = 'reuse_detected') but the actual security event was silent: aTODO: emit audit event auth.refresh_reuse_detectedsat at the spot where the audit-log row should have been written. On a live OP that is the difference between "we noticed a replay attack and shut it down" and "nothing happened, as far as ops can tell."Changes:
crates/bunyip-domain/src/models/audit.rs: addAuditAction::AuthRefreshReuseDetectedand the matching"auth_refresh_reuse_detected"arm inas_str. Not an admin action (system-detected security event), sois_admin_actionstays untouched.crates/bunyip-oidc/src/services/oidc_provider.rs: at the TODO site, after the family-revoke commit and before returningErr(OidcInvalidGrant), build aCreateAuditLogwith actionAuthRefreshReuseDetected, severity Critical,actor_id = old.user_id(so /admin/audit-logs?actor_id=... surfaces the affected user without needing extra context),resource = refresh_token_family/<family_id>, and metadata carrying client_id + the two timestamps that drove the detection (jti_used_at,jti_revoked_at). The actor_id is set directly rather than viawith_actorto avoid a DB lookup for email + role in a security-event hot path; metadata carries the rest.Write is best-effort: an audit-log insert failure logs a
tracing::warn!line and does NOT change theErr(OidcInvalidGrant)returned to the caller. The security event is enforced (family revoked) regardless of whether the log line lands.just check-containerclean (modulo the pre-existingtest_config_defaultsparallel-env-var flake onmain; 188 other tests pass; fmt + clippy + build clean).#BUNYIP-88