or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

aot-native-support.mdauthentication-core.mdauthentication-events.mdauthentication-management.mdauthentication-tokens.mdauthorities.mdauthorization.mdcompromised-password.mdconcurrent-async.mddao-authentication.mdexpression-access-control.mdindex.mdjaas-authentication.mdjackson-serialization.mdmethod-security.mdobservation-metrics.mdone-time-tokens.mdprovisioning.mdsecurity-context.mdsession-management.mduser-details.md
tile.json

authentication-events.mddocs/

Authentication Event Publishing and Listening

Overview

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.

Key Information for Agents

Core Capabilities:

  • Event publishing via AuthenticationEventPublisher interface
  • Default implementation: DefaultAuthenticationEventPublisher using Spring's ApplicationEventPublisher
  • Automatic event mapping from exceptions to specific event types
  • Support for custom exception-to-event mappings
  • Success events: AuthenticationSuccessEvent, InteractiveAuthenticationSuccessEvent
  • Failure events: Multiple specific failure event types (BadCredentials, Disabled, Locked, etc.)
  • Logout events: LogoutSuccessEvent

Key Interfaces and Classes:

  • AuthenticationEventPublisher - Interface: publishAuthenticationSuccess(), publishAuthenticationFailure()
  • DefaultAuthenticationEventPublisher - Default implementation with exception mapping
  • AbstractAuthenticationEvent - Base class for all authentication events
  • AbstractAuthenticationFailureEvent - Base class for failure events
  • AuthenticationSuccessEvent - Published on successful authentication
  • InteractiveAuthenticationSuccessEvent - Published for interactive authentication (not remember-me)
  • LogoutSuccessEvent - Published on successful logout
  • Failure event types: AuthenticationFailureBadCredentialsEvent, AuthenticationFailureDisabledEvent, AuthenticationFailureLockedEvent, etc.

Default Behaviors:

  • ProviderManager uses event publisher if configured via setAuthenticationEventPublisher()
  • Default exception mappings: BadCredentialsExceptionAuthenticationFailureBadCredentialsEvent, etc.
  • Unmapped exceptions: Use default failure event (configurable via setDefaultAuthenticationFailureEvent())
  • Events published synchronously by default (use @Async for async processing)

Threading Model:

  • Events published in calling thread (synchronous)
  • Use @Async annotation for async event processing
  • Event listeners should not throw exceptions (may break authentication flow)

Lifecycle:

  • Events published during authentication process (before/after provider execution)
  • Success events published after successful authentication
  • Failure events published when authentication fails
  • Logout events published by logout handlers

Exceptions:

  • No exceptions thrown by event publisher (events are informational)
  • Event listeners should handle exceptions internally (don't propagate)

Edge Cases:

  • Custom exceptions: Map to custom events via setAdditionalExceptionMappings()
  • Unmapped exceptions: Use default failure event class
  • Event listener failures: Should not affect authentication outcome
  • Async processing: Use @EnableAsync and @Async for non-blocking event handling
  • Multiple listeners: All registered listeners receive events
  • Event ordering: No guaranteed order for multiple listeners

Core Interfaces

AuthenticationEventPublisher

Interface 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)
  • Publishes a successful authentication event
  • Parameters: authentication - The successful authentication
void publishAuthenticationFailure(
    AuthenticationException exception,
    Authentication authentication)
  • Publishes an authentication failure event
  • Parameters:
    • exception - The exception that caused authentication to fail
    • authentication - The authentication request that failed

Package: 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;
    }
}

DefaultAuthenticationEventPublisher

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)
  • Publishes AuthenticationSuccessEvent
void publishAuthenticationFailure(
    AuthenticationException exception,
    Authentication authentication)
  • Maps exception to appropriate failure event and publishes it
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)
  • Sets the Spring ApplicationEventPublisher
void setDefaultAuthenticationFailureEvent(
    Class<? extends AbstractAuthenticationFailureEvent> defaultEvent)
  • Sets the default failure event class for unmapped exceptions
void setAdditionalExceptionMappings(
    Map<Class<? extends AuthenticationException>,
        Class<? extends AbstractAuthenticationFailureEvent>> mappings)
  • Adds custom exception-to-event 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;
    }
}

Authentication Events

Base Event Classes

AbstractAuthenticationEvent

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()
  • Returns the authentication object associated with this event

Package: org.springframework.security.authentication.event

AbstractAuthenticationFailureEvent

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()
  • Returns the exception that caused the authentication failure

Package: org.springframework.security.authentication.event

Success Events

AuthenticationSuccessEvent

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());
    }
}

InteractiveAuthenticationSuccessEvent

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()
  • Returns the class that generated this event

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);
}

Logout Event

LogoutSuccessEvent

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);
}

Failure Events

Spring Security provides specific failure event classes for different authentication exceptions:

AuthenticationFailureBadCredentialsEvent

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);
    }
}

AuthenticationFailureDisabledEvent

Published when user account is disabled.

package org.springframework.security.authentication.event;

class AuthenticationFailureDisabledEvent
    extends AbstractAuthenticationFailureEvent {
    AuthenticationFailureDisabledEvent(Authentication authentication,
        AuthenticationException exception);
}

Triggered by: DisabledException

AuthenticationFailureLockedEvent

Published when user account is locked.

package org.springframework.security.authentication.event;

class AuthenticationFailureLockedEvent
    extends AbstractAuthenticationFailureEvent {
    AuthenticationFailureLockedEvent(Authentication authentication,
        AuthenticationException exception);
}

Triggered by: LockedException

AuthenticationFailureExpiredEvent

Published when user account has expired.

package org.springframework.security.authentication.event;

class AuthenticationFailureExpiredEvent
    extends AbstractAuthenticationFailureEvent {
    AuthenticationFailureExpiredEvent(Authentication authentication,
        AuthenticationException exception);
}

Triggered by: AccountExpiredException

AuthenticationFailureCredentialsExpiredEvent

Published when user credentials have expired.

package org.springframework.security.authentication.event;

class AuthenticationFailureCredentialsExpiredEvent
    extends AbstractAuthenticationFailureEvent {
    AuthenticationFailureCredentialsExpiredEvent(Authentication authentication,
        AuthenticationException exception);
}

Triggered by: CredentialsExpiredException

AuthenticationFailureProviderNotFoundEvent

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

AuthenticationFailureServiceExceptionEvent

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

Event Listeners

Annotation-Based Listeners

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
        );
    }
}

ApplicationListener Interface

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);
    }
}

LoggerListener

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();
}

Integration with ProviderManager

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)
  • Configures the event publisher on ProviderManager

Complete Example: Failed Login Tracking

// 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);
        }
    }
}

Custom Authentication Events

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());
    }
}

Best Practices

  1. Use specific event types - Listen to specific failure events rather than base class
  2. Keep listeners lightweight - Perform heavy operations asynchronously
  3. Handle exceptions - Event listeners should not throw exceptions
  4. Use @Async for heavy operations - Prevent blocking authentication flow
  5. Configure proper event publisher - Ensure DefaultAuthenticationEventPublisher is configured
  6. Add custom mappings - Map custom exceptions to custom events
  7. Log all authentication events - Use LoggerListener for audit trail

Asynchronous Event Processing

Process 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);
    }
}

See Also

  • Authentication Architecture
  • Provider Manager
  • Custom Authentication Providers
  • Spring Framework Event documentation