Spring Boot: Logging Failed Logins

In many applications it’s important to react to failed logins and other security-critical events, for example to log the failed login attempt to a file or to display a captcha after repeated failures. Spring-based applications come with a simple mechanism to access this kind of information using Application Events.

Spring’s Application Events are a variation of the old Observer pattern where an object can subscribe to an Observable to receive notifications. With Application Events, you define a @Component that either implements ApplicationListener or has an @EventListener method that gets the event as a parameter (see below).

There are two event sources available. The first is Spring Security itself which publishes fine-grained events on authentication and authorization. The second one is Spring Boot’s Actuator which listens to Spring Security’s events and maps them to AuditApplicationEvent instances where each contains an AuditEvent. This is part of Spring Boot’s Auditing features.

Listening to AuditApplicationEvent instances is very simple:

public class MyAuditListener { 
    private static final Logger LOG = LoggerFactory.getLogger("security");

    public void onAuditEvent(AuditApplicationEvent event) {
        AuditEvent auditEvent = event.getAuditEvent();
        LOG.info("type={}, principal={}", auditEvent.getType(), auditEvent.getPrincipal());

The AuditEvent has a type property where the following values are relevant for security logging:

  • AUTHENTICATION_SUCCESS (successfully logged in; triggered on each request for stateless applications)
  • AUTHENTICATION_FAILURE (bad credentials etc.)
  • AUTHENTICATION_SWITCH (for user impersonation)
  • AUTHORIZATION_FAILURE (insufficient permissions to access a resource)

The principal property typically contains the user name and there’s a data property for more details.

Usually, I would use a switch statement on the type property, but if you prefer, you can use Spring’s Expression Language to further restrict the listener method:

 @EventListener(condition = "#event.auditEvent.type == 'AUTHENTICATION_FAILURE'")
 public void onAuthFailure(AuditApplicationEvent event) {
     AuditEvent auditEvent = event.getAuditEvent();
     LOG.info("authentication failure, user: {}", auditEvent.getPrincipal());
This entry was posted in java and tagged , . Bookmark the permalink.

11 Responses to Spring Boot: Logging Failed Logins

  1. crusi says:

    In your last code snippet the method name is onAuthSuccess but it’s handling failed loggings

  2. hendisantika says:

    APPLICATION FAILED TO START on Latest Spring Boot.

    Error starting ApplicationContext. To display the conditions report re-run your application with ‘debug’ enabled.
    2020-04-09 09:18:24.326 ERROR 30573 — [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter :



    Parameter 0 of constructor in pl.codeleak.demos.sbt.security.AuditEventListener required a bean of type ‘org.springframework.boot.actuate.audit.AuditEventRepository’ that could not be found.


    Consider defining a bean of type ‘org.springframework.boot.actuate.audit.AuditEventRepository’ in your configuration.


    Any suggest?

  3. hendisantika says:

    Or Maybe You can try to run my repo to see the issue.


    • Matthias says:

      I had a quick look. Go to your AuditEventListener class and remove the constructor, the auditEventRepository attribute, and the call to the repository.

      • hendisantika says:

        After removing as your suggest. It’s working fine now. Unless I can’t login.

        BTW, If We remove the AuditEventRepository We can’t save it the event. Is that OK?


      • Matthias says:

        I don’t believe you have to save events to the repository yourself, the framework should do it for you. Check the /actuator/auditevents endpoint, I think that displays the contents of the repository.

      • hendisantika says:

        I already update my repo. But, I can’t see the Audit Event log in my console. Can You run my repo on your local?


      • Matthias says:

        You probably have to expose the actuator endpoints. Check the documentation, look for the management.endpoints.web.exposure.include property.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s