package com.example.audit.config;
import java.util.Optional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class JpaAuditingConfig {
@Bean
public AuditorAware<String> auditorProvider() {
return new SecurityAuditorAware();
}
static class SecurityAuditorAware implements AuditorAware<String> {
@Override
public Optional<String> getCurrentAuditor() {
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
if (authentication == null
|| !authentication.isAuthenticated()
|| "anonymousUser".equals(authentication.getPrincipal())) {
return Optional.empty();
}
return Optional.of(authentication.getName());
}
}
}
package com.example.audit.domain;
import java.time.Instant;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Auditable {
@CreatedBy
@Column(name = "created_by", updatable = false, length = 100)
private String createdBy;
@CreatedDate
@Column(name = "created_date", updatable = false, nullable = false)
private Instant createdDate;
@LastModifiedBy
@Column(name = "last_modified_by", length = 100)
private String lastModifiedBy;
@LastModifiedDate
@Column(name = "last_modified_date", nullable = false)
private Instant lastModifiedDate;
public String getCreatedBy() {
return createdBy;
}
public Instant getCreatedDate() {
return createdDate;
}
public String getLastModifiedBy() {
return lastModifiedBy;
}
public Instant getLastModifiedDate() {
return lastModifiedDate;
}
}
package com.example.audit.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "documents")
public class Document extends Auditable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(columnDefinition = "text")
private String body;
protected Document() {
}
public Document(String title, String body) {
this.title = title;
this.body = body;
}
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
package com.example.audit.service;
import com.example.audit.domain.Document;
import com.example.audit.repository.DocumentRepository;
import javax.persistence.EntityNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DocumentService {
private final DocumentRepository documents;
public DocumentService(DocumentRepository documents) {
this.documents = documents;
}
@Transactional
public Document create(String title, String body) {
// no audit fields set here; the listener fills created_by/created_date on INSERT
return documents.save(new Document(title, body));
}
@Transactional
public Document rename(Long id, String newTitle) {
Document doc = documents.findById(id)
.orElseThrow(() -> new EntityNotFoundException("document " + id));
doc.setTitle(newTitle);
// last_modified_by/last_modified_date are refreshed on flush of this UPDATE
return doc;
}
}
Spring Data JPA ships a small but powerful auditing feature that fills in bookkeeping columns — who created a row, when, who last touched it, and when — without scattering entity.setUpdatedAt(...) calls across the service layer. This snippet wires that feature end to end and shows the two moving parts that make it work: an AuditorAware bean that answers "who is the current user?" and an auditable base class whose lifecycle hooks Spring populates automatically.
In JpaAuditingConfig, @EnableJpaAuditing turns the feature on and points at the auditorProvider bean via auditorAwareRef. The AuditorAware<String> implementation reads the SecurityContextHolder to derive the current principal's username. It deliberately returns Optional.empty() when there is no authentication or the request is anonymous — that matters because background jobs, migrations, and startup seeders run without a security context, and returning empty lets Spring leave @CreatedBy/@LastModifiedBy null rather than blowing up.
Auditable is a @MappedSuperclass, so its four columns are folded into every subclass table instead of living in a separate table. It carries @EntityListeners(AuditingEntityListener.class), which is the hook Spring uses to intercept persist and update events. @CreatedDate and @LastModifiedBy are set by that listener: creation fields fire once on the initial INSERT, and the modification fields fire on every UPDATE. The createdBy and createdDate columns are marked updatable = false so an accidental re-save can never rewrite the original author or timestamp. Using Instant keeps timestamps timezone-neutral in the database.
Document entity shows the payoff: it simply extends Auditable and declares its own domain fields. Nothing in the entity references auditing directly.
DocumentService demonstrates that the service code stays clean — create and rename never touch the audit columns, yet after save those columns are populated. A key pitfall worth noting is that auditing only fires through the JPA lifecycle, so bulk @Modifying JPQL updates bypass it entirely. This pattern is the idiomatic way to get consistent, tamper-resistant audit metadata across an entire domain model with almost no per-entity code.
Related snips
payload = {
sub: user.id,
iss: 'https://auth.example.com',
aud: 'codesnips-api',
exp: 15.minutes.from_now.to_i,
iat: Time.now.to_i,
JWT issuance and verification without common footguns
import os
import stat
for root, _dirs, files in os.walk('/etc'):
for name in files:
path = os.path.join(root, name)
Python security audit script for exposed risky filesystem state
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
createdAt: String!
GraphQL API with Spring Boot
package com.example.starter.config;
import com.example.starter.properties.CustomProperties;
import com.example.starter.service.CustomService;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
Custom Spring Boot starters
#!/usr/bin/env bash
set -euo pipefail
export VAULT_ADDR="https://vault.internal:8200"
export VAULT_TOKEN="${VAULT_TOKEN:?missing VAULT_TOKEN}"
Secrets management with environment isolation and Vault
import { randomBytes, createHash } from "crypto";
import jwt from "jsonwebtoken";
import { RefreshTokenStore } from "./store";
const ACCESS_SECRET = process.env.ACCESS_SECRET!;
const ACCESS_TTL = "15m";
JWT access + refresh token rotation (conceptual)
Share this code
Here's the card — post it anywhere.