Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring Data JPA auditing: record the actor at the write boundary

Last updated: 5 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

Populate created-by and modified-by fields from authenticated context without treating audit metadata as access control.

Capture actor identity deliberately

A receipt write records who created or last changed it. Enable JPA auditing, attach the auditing listener to the entity, and provide AuditorAware from the current authentication. Store a stable subject identifier, not a display name that changes next month. The audit field answers who the application recorded; it does not prove a caller was authorized. Method security and tenant predicates remain separate.

Define non-request writers

Scheduled jobs, queue consumers and migration programs may have no HTTP security context. Choose an explicit service actor for each path or reject the write; do not silently invent a human identity. An imperative SecurityContextHolder is thread-local, so worker threads need their own authenticated execution context and transaction. Keep the actor in the same transaction as the row so a rollback removes both changes.

Verify the lifecycle

Create and update a receipt through Spring-managed repository methods and assert the two actor fields in a fresh persistence context. Test an unauthenticated write path and a worker job. Bulk JPQL updates bypass ordinary entity listeners, so use a separate audit design for those operations; bulk-update behavior is its own contract.

Implementation contract

Java
@Configuration
@EnableJpaAuditing
class ReceiptAuditConfiguration {
    @Bean AuditorAware<String> currentActor() {
        return () -> Optional.ofNullable(
            SecurityContextHolder.getContext().getAuthentication())
            .filter(actor -> actor.isAuthenticated()
                && !(actor instanceof AnonymousAuthenticationToken))
            .map(Authentication::getName);
    }
}

@Entity
@EntityListeners(AuditingEntityListener.class)
class ReceiptEntity {
    @Id UUID id;
    @CreatedBy @Column(nullable = false) String createdBy;
    @LastModifiedBy String modifiedBy;
}

Cost and verification

Auditing callbacks write extra columns and inspect caller context on entity changes. The overhead is usually small beside SQL, but bulk imports and high-volume updates need a measured design because entity callbacks may not run.

Common Mistakes

  • Do not treat an audit field as proof of authorization.
  • Do not let a background writer silently record an absent or misleading human actor.
  • Do not expect JPQL bulk updates to invoke entity auditing callbacks.

Read next

Spring Data JPA bulk update: the managed entity can still hold the old value, Spring method security: authorization advice runs through the bean proxy, Spring imperative transaction: a worker thread does not inherit it, Spring Data JPA saveAndFlush is a SQL boundary, not a commit, Spring JWT tenant claims: reject missing or malformed ownership before conversion.

spring
spring-data-jpa
jpa-auditing-actor-context
Storage details