skip to content

A team reports authentication events never fire in their app. What are the likely causes and how does the wiring actually work?

level: seniorimportance: should knowfreq 38%

answer

  1. ProviderManager.eventPublisher null-object -> silent no events
  2. hand-built manager -> must setAuthenticationEventPublisher
  3. Boot autoconfigures + wires DefaultAuthenticationEventPublisher
  4. token filter sets context directly -> bypasses manager
  5. custom publisher must delegate to ApplicationEventPublisher

basics

~20 s

Usually the AuthenticationManager has no AuthenticationEventPublisher set — common when you build ProviderManager by hand. Fix it by injecting DefaultAuthenticationEventPublisher (or Boot's autoconfigured one). Also check the failure exception is actually mapped to an event.

solid answer

~40 s

Events are published by the `AuthenticationManager` (`ProviderManager`) through the `AuthenticationEventPublisher` it holds. Spring Boot auto-configures a `DefaultAuthenticationEventPublisher` bean and wires it into the framework-built `AuthenticationManager`, so events fire by default. They stop firing when you take over: constructing a `ProviderManager` manually and never calling `setAuthenticationEventPublisher(...)`, or defining your own `AuthenticationManager` bean that isn't wired to the publisher. Other causes: the authentication path bypasses the manager entirely (custom filter that sets the `SecurityContext` directly), a custom `AuthenticationEventPublisher` bean that doesn't delegate to the `ApplicationEventPublisher`, listeners in a different `ApplicationContext`, or failure exceptions that aren't in the publisher's mapping. Fix by injecting the publisher into the manager, or letting `AuthenticationManagerBuilder`/Boot build it for you.

code

java · 15 lines
java
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authentication.*;
import java.util.List;

@Bean
AuthenticationManager authenticationManager(
        MyAuthenticationProvider provider,
        ApplicationEventPublisher applicationEventPublisher) {

    ProviderManager manager = new ProviderManager(List.of(provider));
    // WITHOUT this line, no AuthenticationSuccess/Failure events are ever published:
    manager.setAuthenticationEventPublisher(
            new DefaultAuthenticationEventPublisher(applicationEventPublisher));
    return manager;
}

go deeper

for a junior

Know the manager must have a publisher for events to fire.

for a middle

Identify the hand-built-manager-missing-publisher cause and fix it.

for a senior

Enumerate the full set of failure modes including bypass paths and non-delegating publishers.

for a principal

Establish conventions so all authentication paths (form, token, OAuth) produce consistent audit events.

## The publishing chain 1. A filter (e.g. `UsernamePasswordAuthenticationFilter`) or your code calls `authenticationManager.authenticate(token)`. 2. `ProviderManager.authenticate(...)` iterates providers. On success it calls `this.eventPublisher.publishAuthenticationSuccess(result)`; on an `AuthenticationException` it calls `this.eventPublisher.publishAuthenticationFailure(ex, token)`. 3. `this.eventPublisher` is an `AuthenticationEventPublisher`. If it's the `NullEventPublisher` sentinel (the internal default when none is set), **nothing happens**. 4. `DefaultAuthenticationEventPublisher` delegates to the Spring `ApplicationEventPublisher`, which dispatches to `@EventListener` beans. ## Why it usually works in Boot Spring Boot's security auto-configuration registers a `DefaultAuthenticationEventPublisher` bean, and the `AuthenticationConfiguration`/`AuthenticationManagerBuilder` used to build the default `AuthenticationManager` wires that publisher in. So an app that relies on the framework-provided manager gets events for free. ## The failure modes **A. Hand-built `ProviderManager` without a publisher.** The single most common cause: ```java var manager = new ProviderManager(List.of(myProvider)); // missing: manager.setAuthenticationEventPublisher(publisher); ``` Here `eventPublisher` stays the internal null-object → no events. Fix: ```java var manager = new ProviderManager(List.of(myProvider)); manager.setAuthenticationEventPublisher( new DefaultAuthenticationEventPublisher(applicationEventPublisher)); ``` **B. Custom `AuthenticationManager` bean not wired.** If you expose your own `@Bean AuthenticationManager`, you own the wiring — Boot won't retrofit a publisher. **C. Authentication bypasses the manager.** OAuth2 login, JWT resource-server, or a custom filter that validates a token and sets `SecurityContextHolder` directly never calls a `ProviderManager`, so `AuthenticationSuccessEvent` is not published. (JWT bearer-token authentication via `BearerTokenAuthenticationFilter`/`AuthenticationManager` can publish, but many hand-rolled JWT filters skip the manager.) For those paths, publish events yourself or use the relevant handlers. **D. Custom publisher that doesn't delegate.** Someone replaced the `AuthenticationEventPublisher` bean with an implementation that logs but never forwards to `ApplicationEventPublisher` → listeners never see events. **E. Unmapped failure exception.** Success fires but failures don't, because the thrown exception type isn't in `DefaultAuthenticationEventPublisher`'s map and no default failure event is set (see the mapping question). **F. Wrong context / not a bean.** The listener class isn't a Spring bean, or lives in a child/parent context that doesn't receive the events. ## `AuthenticationSuccessEvent` vs `InteractiveAuthenticationSuccessEvent` Worth knowing during diagnosis: `AuthenticationSuccessEvent` is published by the `AuthenticationManager`; `InteractiveAuthenticationSuccessEvent` is published later by `AbstractAuthenticationProcessingFilter` after a *form/interactive* login succeeds and the context is stored. If someone only listens for one, they may conclude events are "missing" when they're simply listening for the wrong type for that authentication path. ## Diagnostic checklist - Is the login going through a `ProviderManager`? Set a breakpoint in `ProviderManager.authenticate`. - Does that manager have a non-null, delegating `AuthenticationEventPublisher`? - Is the listener a Spring-managed bean in the right context? - For failures, is the exception type mapped? - Are you listening for the event type that matches your authentication mechanism?

  • Your JWT filter validates the token and sets SecurityContextHolder directly — why no AuthenticationSuccessEvent?
    That path never calls a ProviderManager, which is what publishes the event. Either authenticate through an AuthenticationManager or publish the event yourself via ApplicationEventPublisher.
  • What's the difference between AuthenticationSuccessEvent and InteractiveAuthenticationSuccessEvent?
    The former is fired by the AuthenticationManager for any successful authentication; the latter is fired by AbstractAuthenticationProcessingFilter only for interactive (form-based) logins after the context is stored.

saying these in an interview costs you the question

  • Assuming events fire regardless of how authentication is performed
  • Not realizing a hand-built ProviderManager defaults to a no-op event publisher
  • Believing token/OAuth filters that set the context directly still emit AuthenticationSuccessEvent

context