java 165 lines · 4 tabs

Automatic JPA Auditing in Spring Boot with @CreatedDate and @LastModifiedBy

Shared by codesnips Aug 2026
4 tabs
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());
        }
    }
}
4 files · java Explain with highlit

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

ruby
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

jwt authentication api
by Kai Nakamura 2 tabs
python
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

python auditing host-security
by Kai Nakamura 1 tab
graphql
type User {
    id: ID!
    name: String!
    email: String!
    posts: [Post!]!
    createdAt: String!

GraphQL API with Spring Boot

java graphql spring-boot
by David Kumar 3 tabs
java
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

java spring-boot starter
by David Kumar 4 tabs
bash
#!/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

secrets-management vault environment-variables
by Kai Nakamura 1 tab
typescript
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)

security node jwt
by codesnips 3 tabs

Share this code

Here's the card — post it anywhere.

Automatic JPA Auditing in Spring Boot with @CreatedDate and @LastModifiedBy — share card
Link copied