docs
Spring Security provides a comprehensive event system for authentication lifecycle events. Applications can publish and listen to authentication success, failure, and logout events using Spring's standard event infrastructure.
Core Capabilities:
AuthenticationEventPublisher interfaceDefaultAuthenticationEventPublisher using Spring's ApplicationEventPublisherAuthenticationSuccessEvent, InteractiveAuthenticationSuccessEventLogoutSuccessEventKey Interfaces and Classes:
AuthenticationEventPublisher - Interface: publishAuthenticationSuccess(), publishAuthenticationFailure()DefaultAuthenticationEventPublisher - Default implementation with exception mappingAbstractAuthenticationEvent - Base class for all authentication eventsAbstractAuthenticationFailureEvent - Base class for failure eventsAuthenticationSuccessEvent - Published on successful authenticationInteractiveAuthenticationSuccessEvent - Published for interactive authentication (not remember-me)LogoutSuccessEvent - Published on successful logoutAuthenticationFailureBadCredentialsEvent, AuthenticationFailureDisabledEvent, AuthenticationFailureLockedEvent, etc.Default Behaviors:
ProviderManager uses event publisher if configured via setAuthenticationEventPublisher()BadCredentialsException → AuthenticationFailureBadCredentialsEvent, etc.setDefaultAuthenticationFailureEvent())@Async for async processing)Threading Model:
@Async annotation for async event processingLifecycle:
Exceptions:
Edge Cases:
setAdditionalExceptionMappings()@EnableAsync and @Async for non-blocking event handlingInterface for publishing authentication events.
package org.springframework.security.authentication;
interface AuthenticationEventPublisher {
void publishAuthenticationSuccess(Authentication authentication);
void publishAuthenticationFailure(AuthenticationException exception,
Authentication authentication);
}Description: Strategy interface for publishing authentication-related events.
Methods:
void publishAuthenticationSuccess(Authentication authentication)authentication - The successful authenticationvoid publishAuthenticationFailure(
AuthenticationException exception,
Authentication authentication)exception - The exception that caused authentication to failauthentication - The authentication request that failedPackage: org.springframework.security.authentication
Example:
public class CustomAuthenticationProvider implements AuthenticationProvider {
private AuthenticationEventPublisher eventPublisher;
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
try {
// Perform authentication
Authentication result = performAuthentication(authentication);
eventPublisher.publishAuthenticationSuccess(result);
return result;
} catch (BadCredentialsException ex) {
eventPublisher.publishAuthenticationFailure(ex, authentication);
throw ex;
}
}
public void setAuthenticationEventPublisher(
AuthenticationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
}Default implementation that publishes events using Spring's ApplicationEventPublisher.
package org.springframework.security.authentication;
class DefaultAuthenticationEventPublisher
implements AuthenticationEventPublisher, ApplicationEventPublisherAware {
DefaultAuthenticationEventPublisher();
DefaultAuthenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
void publishAuthenticationSuccess(Authentication authentication);
void publishAuthenticationFailure(AuthenticationException exception,
Authentication authentication);
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
void setDefaultAuthenticationFailureEvent(
Class<? extends AbstractAuthenticationFailureEvent> defaultEvent);
void setAdditionalExceptionMappings(
Map<Class<? extends AuthenticationException>,
Class<? extends AbstractAuthenticationFailureEvent>> mappings);
}Description: Default event publisher that maps exceptions to Spring ApplicationEvents.
Methods:
void publishAuthenticationSuccess(Authentication authentication)AuthenticationSuccessEventvoid publishAuthenticationFailure(
AuthenticationException exception,
Authentication authentication)void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)void setDefaultAuthenticationFailureEvent(
Class<? extends AbstractAuthenticationFailureEvent> defaultEvent)void setAdditionalExceptionMappings(
Map<Class<? extends AuthenticationException>,
Class<? extends AbstractAuthenticationFailureEvent>> mappings)Package: org.springframework.security.authentication
Example:
@Configuration
public class SecurityConfig {
@Bean
public AuthenticationEventPublisher authenticationEventPublisher(
ApplicationEventPublisher applicationEventPublisher) {
DefaultAuthenticationEventPublisher publisher =
new DefaultAuthenticationEventPublisher(applicationEventPublisher);
// Add custom exception mapping
Map<Class<? extends AuthenticationException>,
Class<? extends AbstractAuthenticationFailureEvent>> mappings =
new HashMap<>();
mappings.put(CustomAuthenticationException.class,
CustomAuthenticationFailureEvent.class);
publisher.setAdditionalExceptionMappings(mappings);
return publisher;
}
}Base class for all authentication events.
package org.springframework.security.authentication.event;
abstract class AbstractAuthenticationEvent extends ApplicationEvent {
AbstractAuthenticationEvent(Authentication authentication);
Authentication getAuthentication();
}Methods:
Authentication getAuthentication()Package: org.springframework.security.authentication.event
Base class for authentication failure events.
package org.springframework.security.authentication.event;
abstract class AbstractAuthenticationFailureEvent
extends AbstractAuthenticationEvent {
AbstractAuthenticationFailureEvent(Authentication authentication,
AuthenticationException exception);
AuthenticationException getException();
}Methods:
AuthenticationException getException()Package: org.springframework.security.authentication.event
Published when authentication succeeds.
package org.springframework.security.authentication.event;
class AuthenticationSuccessEvent extends AbstractAuthenticationEvent {
AuthenticationSuccessEvent(Authentication authentication);
}Description: Event indicating successful authentication.
Example:
@Component
public class AuthenticationSuccessListener {
@EventListener
public void onAuthenticationSuccess(AuthenticationSuccessEvent event) {
Authentication auth = event.getAuthentication();
String username = auth.getName();
System.out.println("User logged in: " + username);
// Log successful login
auditLog.logSuccessfulLogin(username, LocalDateTime.now());
}
}Published when interactive authentication succeeds (e.g., form login, not remember-me).
package org.springframework.security.authentication.event;
class InteractiveAuthenticationSuccessEvent
extends AuthenticationSuccessEvent {
InteractiveAuthenticationSuccessEvent(
Authentication authentication,
Class<?> generatedBy);
Class<?> getGeneratedBy();
}Methods:
Class<?> getGeneratedBy()Description: Event for interactive authentication (user explicitly provided credentials).
Example:
@EventListener
public void onInteractiveLogin(InteractiveAuthenticationSuccessEvent event) {
Authentication auth = event.getAuthentication();
String username = auth.getName();
// Update last login time only for interactive logins
userService.updateLastLoginTime(username, Instant.now());
// Send login notification email
emailService.sendLoginNotification(username);
}Published when logout completes successfully.
package org.springframework.security.authentication.event;
class LogoutSuccessEvent extends AbstractAuthenticationEvent {
LogoutSuccessEvent(Authentication authentication);
}Description: Event indicating successful logout.
Example:
@EventListener
public void onLogoutSuccess(LogoutSuccessEvent event) {
Authentication auth = event.getAuthentication();
String username = auth.getName();
// Log logout
auditLog.logLogout(username, LocalDateTime.now());
// Clean up user session data
sessionDataService.cleanup(username);
}Spring Security provides specific failure event classes for different authentication exceptions:
Published when credentials are invalid.
package org.springframework.security.authentication.event;
class AuthenticationFailureBadCredentialsEvent
extends AbstractAuthenticationFailureEvent {
AuthenticationFailureBadCredentialsEvent(Authentication authentication,
AuthenticationException exception);
}Triggered by: BadCredentialsException
Example:
@EventListener
public void onBadCredentials(AuthenticationFailureBadCredentialsEvent event) {
Authentication auth = event.getAuthentication();
String username = auth.getName();
// Track failed login attempts
loginAttemptService.recordFailedAttempt(username);
// Lock account after multiple failures
if (loginAttemptService.getFailedAttempts(username) >= 5) {
userService.lockAccount(username);
alertService.sendAccountLockedEmail(username);
}
}Published when user account is disabled.
package org.springframework.security.authentication.event;
class AuthenticationFailureDisabledEvent
extends AbstractAuthenticationFailureEvent {
AuthenticationFailureDisabledEvent(Authentication authentication,
AuthenticationException exception);
}Triggered by: DisabledException
Published when user account is locked.
package org.springframework.security.authentication.event;
class AuthenticationFailureLockedEvent
extends AbstractAuthenticationFailureEvent {
AuthenticationFailureLockedEvent(Authentication authentication,
AuthenticationException exception);
}Triggered by: LockedException
Published when user account has expired.
package org.springframework.security.authentication.event;
class AuthenticationFailureExpiredEvent
extends AbstractAuthenticationFailureEvent {
AuthenticationFailureExpiredEvent(Authentication authentication,
AuthenticationException exception);
}Triggered by: AccountExpiredException
Published when user credentials have expired.
package org.springframework.security.authentication.event;
class AuthenticationFailureCredentialsExpiredEvent
extends AbstractAuthenticationFailureEvent {
AuthenticationFailureCredentialsExpiredEvent(Authentication authentication,
AuthenticationException exception);
}Triggered by: CredentialsExpiredException
Published when no AuthenticationProvider supports the authentication request.
package org.springframework.security.authentication.event;
class AuthenticationFailureProviderNotFoundEvent
extends AbstractAuthenticationFailureEvent {
AuthenticationFailureProviderNotFoundEvent(Authentication authentication,
AuthenticationException exception);
}Triggered by: ProviderNotFoundException
Published when authentication service encounters an error.
package org.springframework.security.authentication.event;
class AuthenticationFailureServiceExceptionEvent
extends AbstractAuthenticationFailureEvent {
AuthenticationFailureServiceExceptionEvent(Authentication authentication,
AuthenticationException exception);
}Triggered by: AuthenticationServiceException
All failure events are in package: org.springframework.security.authentication.event
Use Spring's @EventListener annotation for simple event handling:
@Component
public class AuthenticationEventListener {
private final AuditService auditService;
private final NotificationService notificationService;
public AuthenticationEventListener(
AuditService auditService,
NotificationService notificationService) {
this.auditService = auditService;
this.notificationService = notificationService;
}
@EventListener
public void onSuccess(AuthenticationSuccessEvent event) {
String username = event.getAuthentication().getName();
auditService.logSuccess(username);
}
@EventListener
public void onFailure(AbstractAuthenticationFailureEvent event) {
String username = event.getAuthentication().getName();
AuthenticationException exception = event.getException();
auditService.logFailure(username, exception.getMessage());
}
@EventListener
public void onBadCredentials(
AuthenticationFailureBadCredentialsEvent event) {
String username = event.getAuthentication().getName();
notificationService.alertSecurityTeam(
"Multiple failed login attempts for: " + username
);
}
}Implement ApplicationListener for type-safe event handling:
@Component
public class LoginAttemptListener
implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
private final LoginAttemptService loginAttemptService;
public LoginAttemptListener(LoginAttemptService loginAttemptService) {
this.loginAttemptService = loginAttemptService;
}
@Override
public void onApplicationEvent(
AuthenticationFailureBadCredentialsEvent event) {
String username = event.getAuthentication().getName();
loginAttemptService.loginFailed(username);
}
}Built-in listener that logs authentication events.
package org.springframework.security.authentication.event;
class LoggerListener implements ApplicationListener<AbstractAuthenticationEvent> {
LoggerListener();
}Description: Logs authentication events to the application log.
Configuration:
@Bean
public LoggerListener loggerListener() {
return new LoggerListener();
}The ProviderManager automatically uses an AuthenticationEventPublisher if configured:
@Bean
public AuthenticationManager authenticationManager(
AuthenticationEventPublisher eventPublisher) {
ProviderManager manager = new ProviderManager(
Arrays.asList(authenticationProvider())
);
manager.setAuthenticationEventPublisher(eventPublisher);
return manager;
}Methods:
void setAuthenticationEventPublisher(
AuthenticationEventPublisher eventPublisher)// Service to track failed login attempts
@Service
public class LoginAttemptService {
private static final int MAX_ATTEMPTS = 5;
private final LoadingCache<String, Integer> attemptsCache;
public LoginAttemptService() {
this.attemptsCache = CacheBuilder.newBuilder()
.expireAfterWrite(1, TimeUnit.DAYS)
.build(new CacheLoader<String, Integer>() {
@Override
public Integer load(String key) {
return 0;
}
});
}
public void loginSucceeded(String username) {
attemptsCache.invalidate(username);
}
public void loginFailed(String username) {
int attempts = attemptsCache.getUnchecked(username);
attemptsCache.put(username, attempts + 1);
}
public boolean isBlocked(String username) {
return attemptsCache.getUnchecked(username) >= MAX_ATTEMPTS;
}
}
// Event listener for failed logins
@Component
public class FailedLoginListener {
private final LoginAttemptService loginAttemptService;
private final UserRepository userRepository;
@EventListener
public void onAuthenticationFailure(
AuthenticationFailureBadCredentialsEvent event) {
String username = event.getAuthentication().getName();
loginAttemptService.loginFailed(username);
if (loginAttemptService.isBlocked(username)) {
User user = userRepository.findByUsername(username);
if (user != null && user.isEnabled()) {
user.setEnabled(false);
userRepository.save(user);
System.out.println("Account locked: " + username);
}
}
}
}
// Event listener for successful logins
@Component
public class SuccessfulLoginListener {
private final LoginAttemptService loginAttemptService;
private final UserRepository userRepository;
@EventListener
public void onAuthenticationSuccess(AuthenticationSuccessEvent event) {
String username = event.getAuthentication().getName();
loginAttemptService.loginSucceeded(username);
// Update last login timestamp
User user = userRepository.findByUsername(username);
if (user != null) {
user.setLastLogin(Instant.now());
userRepository.save(user);
}
}
}Create custom events by extending the base classes:
// Custom event
public class CustomAuthenticationEvent extends AbstractAuthenticationEvent {
private final String additionalInfo;
public CustomAuthenticationEvent(
Authentication authentication,
String additionalInfo) {
super(authentication);
this.additionalInfo = additionalInfo;
}
public String getAdditionalInfo() {
return additionalInfo;
}
}
// Custom failure event
public class TwoFactorAuthenticationFailureEvent
extends AbstractAuthenticationFailureEvent {
public TwoFactorAuthenticationFailureEvent(
Authentication authentication,
AuthenticationException exception) {
super(authentication, exception);
}
}
// Publisher
@Service
public class CustomAuthenticationService {
private final ApplicationEventPublisher eventPublisher;
public void authenticate(String username, String code) {
Authentication auth = createAuthentication(username, code);
// Publish custom event
eventPublisher.publishEvent(
new CustomAuthenticationEvent(auth, "2FA verification")
);
}
}
// Listener
@Component
public class CustomEventListener {
@EventListener
public void onCustomEvent(CustomAuthenticationEvent event) {
System.out.println("Custom auth: " +
event.getAuthentication().getName() +
" - " + event.getAdditionalInfo());
}
}DefaultAuthenticationEventPublisher is configuredLoggerListener for audit trailProcess events asynchronously to avoid blocking authentication:
@Configuration
@EnableAsync
public class AsyncEventConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.initialize();
return executor;
}
}
@Component
public class AsyncAuthenticationEventListener {
@Async
@EventListener
public void onAuthenticationSuccess(AuthenticationSuccessEvent event) {
// Heavy operation performed asynchronously
sendWelcomeEmail(event.getAuthentication().getName());
}
@Async
@EventListener
public void onAuthenticationFailure(
AbstractAuthenticationFailureEvent event) {
// Asynchronous security alerting
analyzeAndAlertSecurityTeam(event);
}
}