1
0
Files
spring-security-demo/README.md
Ankur b7244ff9a2 Add virtual-thread, structured-concurrency demos for the Spring Security context propagation guide
Three verified programs (JDK 25, Spring Security 7.1.1, Spring Boot 4.1.1 dependency
versions) backing the ankurm.com post: InheritableThreadLocal across thread models,
@Async on a virtual-thread SimpleAsyncTaskExecutor (DelegatingSecurityContextExecutor
vs ContextPropagatingTaskDecorator), and StructuredTaskScope.fork() propagation.
Captured console output and docs chapters included.
2026-08-24 21:48:47 +05:30

2.8 KiB

spring-security-demo

Companion repo for Spring Security Context Propagation - Complete Guide on ankurm.com. Three small, dependency-light programs that answer one question each: does a Spring Security SecurityContext survive a specific thread hand-off? No web server, no HTTP -- every scenario sets an Authentication on the calling thread and checks whether the other side of the hand-off can see it.

Verified versions

Component Version
JDK 25 (Temurin 25.0.4.1+1), LTS, GA 2025-09-16
Spring Boot (reference target) 4.1.1
Spring Framework 7.0.9
Spring Security 7.1.1
io.micrometer:context-propagation 1.2.1 (as managed by Boot 4.1.1's BOM)

StructuredTaskScope is a preview API on JDK 25 (JEP 505, fifth preview) and remains preview through JDK 26 (JEP 525, sixth preview) -- every build/run command below needs --enable-preview.

Quickstart

mvn dependency:build-classpath -Dmdep.outputFile=cp.txt
javac --release 25 --enable-preview -cp "$(cat cp.txt)" -d target/classes $(find src -name '*.java')
java --enable-preview -cp "target/classes:$(cat cp.txt)" com.ankurm.vt.Demo1PlainThreadLocal

Or just run everything and regenerate the captured output: scripts/run-all.sh.

What each demo shows

Demo Question Chapter
Demo1PlainThreadLocal Does InheritableThreadLocal behave differently for a pooled platform thread vs. a fresh virtual thread? (No Spring.) docs/01
Demo2AsyncVirtualThreads Does the Boot-4.1-style virtual-thread @Async executor propagate SecurityContext, and what four fixes change? docs/02
Demo3StructuredConcurrency Does a StructuredTaskScope.fork() subtask see the parent's SecurityContext? docs/03

Captured output

Every number and log line in the blog post traces back to one of these, produced by scripts/run-all.sh, not retyped:

The one-line summary of all three chapters

SecurityContextHolder is a ThreadLocal. Nothing about virtual threads or structured concurrency changes that. What changed is that virtual threads are never pooled, so MODE_INHERITABLETHREADLOCAL's old danger (stale context on a reused pool worker) doesn't apply to them -- and Spring Security 6.5 gave SecurityContextHolder a Micrometer ThreadLocalAccessor, so ContextPropagatingTaskDecorator / ContextSnapshot.wrap(...) now propagate it automatically, alongside MDC and tracing context, without a DelegatingSecurityContext* wrapper.