Athena — europeLogin/decisions/ADR-002-audit-actor-attribution.md

ADR-002: Explicit audit calls for auth events instead of @Auditable AOP

Date: 2026-03-27 Status: Accepted

Context

The @Auditable AOP annotation was designed to intercept any annotated method and record an audit event. It works well for generic events (onboarding steps, company creation) where the target ID is a simple method parameter.

For authentication events (login, logout), the audit event must include:

  • actorEmail
  • actorKvkNumber
  • actorRole
  • assuranceLevelUsed

The AOP aspect cannot derive these from a method parameter alone — it would need to load the Company and AuthorizedRepresentative after the fact.

The same issue appeared for TokenService.revokeSession(sessionToken): the aspect only has the raw session token string, not the KvK number or role. As a result, audit events for logout were recorded with actorKvkNumber = null and were not findable via AuditRepository.findByActorKvkNumber().

Decision

For auth events (LOGIN_SUCCESS, LOGIN_FAILURE, LOGOUT), call auditService.record() directly with full actor info, rather than relying on @Auditable.

  • CompanyAuthService.authenticateCompany() — removed @Auditable, now calls auditService.record() at each failure point and on success with explicit kvk/email/role/level
  • TokenService.revokeSession() — removed @Auditable, now calls auditService.record() inside the .map() block once the session entity is loaded (KvK and role available)

Keep @Auditable for: onboarding steps, company registration, and other events where the AOP target ID is sufficient.

Consequences

  • Auth audit events always have correct actorKvkNumber — queryable by KvK
  • Slightly more boilerplate in CompanyAuthService and TokenService
  • Risk: if a new auth method is added without explicit audit calls, it goes unaudited — mitigated by code review

Reacties

Nog geen reacties