SecurityContextHolder y propagación del contexto

Intermedio
Spring Boot
Spring Boot
Actualizado: 04/05/2026

Diagrama: tutorial-spring-security-securitycontextholder

Que es SecurityContextHolder

SecurityContextHolder es la clase estática con la que Spring Security expone el contexto de seguridad del hilo en ejecución. En su interior guarda un SecurityContext que contiene el Authentication del usuario actual, con su principal, credenciales y autoridades.

SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Collection<? extends GrantedAuthority> roles = authentication.getAuthorities();

Como el acceso es estático, el contexto esta disponible desde servicios, repositorios o componentes Spring sin inyectar nada. Es la forma canonica de saber quien esta ejecutando una petición en este momento.

Strategies de almacenamiento

La estrategia por defecto es MODE_THREADLOCAL, que guarda el contexto en un ThreadLocal. Funciona perfectamente en el stack servlet clásico porque cada petición consume un único hilo del pool del contenedor.

Cuando la aplicación delega trabajo a hilos asíncronos, la estrategia puede cambiarse:

SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);

Esta modalidad propaga el contexto a hilos hijos creados con new Thread(...). En cambio, no cubre pools gestionados por ExecutorService, donde conviene envolver las tareas con DelegatingSecurityContextRunnable o DelegatingSecurityContextExecutor.

Uso con @Async y virtual threads

Spring Security ofrece integración directa con @Async. Basta con marcar el bean SecurityContextHolderStrategy y configurar el TaskExecutor para que propague el contexto:

@Bean
DelegatingSecurityContextAsyncTaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor delegate = new ThreadPoolTaskExecutor();
    delegate.initialize();
    return new DelegatingSecurityContextAsyncTaskExecutor(delegate);
}

Con virtual threads de Java 21 o Java 25 en Project Loom, el contexto se propaga correctamente mientras se use la estrategia MODE_THREADLOCAL, ya que cada virtual thread obtiene su propio almacenamiento local.

Acceso desde controladores

En controladores REST conviene evitar SecurityContextHolder directo y usar las abstracciones de Spring MVC.

@GetMapping("/me")
public UserResponse currentUser(@AuthenticationPrincipal UserDetails principal) {
    return new UserResponse(principal.getUsername(), principal.getAuthorities());
}

@AuthenticationPrincipal extrae el principal del contexto y lo inyecta como parámetro, lo que mejora la testabilidad al poder pasar un mock desde un @WebMvcTest.

Propagación a tareas asíncronas

SecurityContext vive en ThreadLocal, por lo que no se copia automáticamente al crear un hilo mediante new Thread(...) ni al enviar tareas a un ExecutorService externo. Spring Security expone decoradores para propagar el contexto de forma transparente.

@Configuration
public class AsyncConfig {

    @Bean
    ThreadPoolTaskExecutor applicationTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(8);
        executor.setMaxPoolSize(16);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("biz-");
        executor.initialize();
        return executor;
    }

    @Bean
    DelegatingSecurityContextAsyncTaskExecutor securityAwareExecutor(
            ThreadPoolTaskExecutor delegate) {
        return new DelegatingSecurityContextAsyncTaskExecutor(delegate);
    }
}

@Service
public class AuditoriaService {

    private final DelegatingSecurityContextAsyncTaskExecutor executor;

    public AuditoriaService(DelegatingSecurityContextAsyncTaskExecutor executor) {
        this.executor = executor;
    }

    public void registrarEnSegundoPlano(String evento) {
        executor.execute(() -> {
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            // auth ya esta propagado aqui, aunque estemos en un hilo distinto
        });
    }
}

Flujo de propagación con virtual threads

Con virtual threads cada petición obtiene un hilo propio que no se comparte entre peticiones, por lo que el contexto permanece aislado. Los executors de virtual threads (Executors.newVirtualThreadPerTaskExecutor) también se pueden envolver con DelegatingSecurityContextExecutor para propagar el contexto a tareas lanzadas desde dentro de la petición.

Buenas prácticas en proyectos corporativos

  • No persistas objetos Authentication en base de datos ni los serialices a JSON: contienen credenciales y pueden filtrarse en logs.
  • Si necesitas username en servicios o repositorios, inyecta Supplier<String> con la función () -> SecurityContextHolder.getContext().getAuthentication().getName() en vez de tocar el holder directamente; facilita el testing.
  • Borra el contexto explicitamente con SecurityContextHolder.clearContext() al final de tareas batch que modifiquen la autenticación en el hilo.

Casos de uso B2B

  • Banca: auditoría transversal que registra usuario, IP y horario de cada operación critica leyendo el contexto desde un aspecto AOP.
  • Logistica y ecommerce: propagación del usuario a tareas asíncronas que emiten eventos Kafka, de modo que los consumidores puedan reconstruir quien disparo el evento.
  • Sector público: integración con sistemas de trazabilidad regulatoria (eIDAS2, DORA) donde cada operación debe quedar firmada con la identidad del usuario original aunque se procese en segundo plano.
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Spring Boot es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Spring Boot

Explora más contenido relacionado con Spring Boot y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Entender el rol de SecurityContextHolder en Spring Security. Acceder al usuario autenticado desde cualquier capa. Configurar strategies que propaguen el contexto a hilos asíncronos.