Spring Security Custom AuthenticationFailureHandler

Last Updated : 1 Jun, 2026

In Spring Security, AuthenticationFailureHandler is used to handle actions when user authentication fails. A custom AuthenticationFailureHandler allows developers to define their own logic, such as displaying custom error messages, logging failed login attempts, or redirecting users to specific pages.

  • Handles login failures when authentication is unsuccessful.
  • Allows custom error messages and redirections based on failure reasons.
  • Improves security and user experience by implementing custom failure handling logic.

Implementation of Custom AuthenticationFailureHandler in Spring Security

Follow the steps below to implement a Custom AuthenticationFailureHandler in a Spring Boot application.

Step 1: Create a Spring Boot Project

Create a Spring Boot project and add the following dependencies:

  • Spring Web
  • Spring Security
  • Spring Data MongoDB
  • Spring Boot DevTools
  • Lombok

pom.xml

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg</groupId>
    <artifactId>CustomAuthenticationFailure</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>CustomAuthenticationFailure</name>
    <description>CustomAuthenticationFailure</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

File Structure:

Project Structure

Step 2: Configure MongoDB Database

Open the application.properties file and configure the MongoDB connection.

spring.data.mongodb.uri=mongodb://localhost:27017/CustomData

Step 3: Create User Model

Create a package named model and create a User class.

  • Represents user data stored in MongoDB.
  • Uses Lombok annotations to generate boilerplate code.
  • Maps the class to the users collection.
Java
package com.gfg.customauthenticationfailure.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

// The @Data annotation generates getters, setters, toString, equals, and hashCode methods automatically
@Data
// The @AllArgsConstructor annotation generates a constructor with all arguments
@AllArgsConstructor
// The @NoArgsConstructor annotation generates a constructor with no arguments
@NoArgsConstructor
// The @Document annotation marks this class as a document in a MongoDB collection
@Document(collection = "users")
public class User {
    // The @Id annotation marks this field as the primary key of the document
    @Id
    private String id;
    // The @Field annotation specifies the name of the field in the MongoDB document
    // If not specified, the field name will be the same as the variable name
    private String username;
    private String password;
}

Step 4: Create User Repository

Create a package named repository and create UserRepository.

  • Extends MongoRepository.
  • Provides database operations.
  • Includes a method to find users by username.
Java
package com.gfg.customauthenticationfailure.repository;

import com.gfg.customauthenticationfailure.model.User;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

// The @Repository annotation marks this interface as a repository component in Spring
@Repository
public interface UserRepository extends MongoRepository<User, String> {

    // Method to find a user by their username
    User findByUsername(String username);
}

Step 5: Create User Service

Create a package named service and create UserService.

  • Contains business logic.
  • Retrieves user details from MongoDB.
  • Uses UserRepository.
Java
package com.gfg.customauthenticationfailure.service;

import com.gfg.customauthenticationfailure.model.User;
import com.gfg.customauthenticationfailure.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

// The @Service annotation marks this class as a service component in Spring
@Service
public class UserService {

    // Autowire the UserRepository to interact with the database
    @Autowired
    private UserRepository userRepository;

    // Method to find a user by their username
    public User findByUsername(String username) {
        // Call the findByUsername method of the userRepository to find the user by username
        return userRepository.findByUsername(username);
    }
}

Step 6: Create Custom AuthenticationFailureHandler

Create a package named securityconfig and create CustomAuthenticationFailureHandler.

  • Implements AuthenticationFailureHandler.
  • Handles failed login attempts.
  • Redirects users to a custom error page.
Java
package com.gfg.customauthenticationfailure.securityconfig;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

import java.io.IOException;

// Implement the AuthenticationFailureHandler interface to create a custom authentication failure handler
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {

    // Override the onAuthenticationFailure method to handle authentication failure
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        // Your custom failure handling logic goes here

        // For example, redirect the user to the login page with an error message in the URL
        response.sendRedirect("/login?error=true");
    }
}

Step 7: Configure Spring Security

Create a class named SecurityConfig.

  • Enables Spring Security.
  • Configures login and logout functionality.
  • Registers the custom failure handler.
Java
package com.gfg.customauthenticationfailure.securityconfig;

import com.gfg.customauthenticationfailure.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private UserRepository userRepository;

    // Override the configure method to specify which URLs are allowed and which are not
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .requestMatchers("/signup").permitAll() // Allow requests to /signup without authentication
                .anyRequest().authenticated() // Require authentication for all other requests
                .and()
                .formLogin() // Enable form-based login
                .loginPage("/login") // Specify the login page URL
                .failureHandler(new CustomAuthenticationFailureHandler()) // Specify the failure handler for login attempts
                .permitAll() // Allow anyone to access the login page
                .and()
                .logout() // Enable logout functionality
                .permitAll(); // Allow anyone to access the logout URL
    }

    // Create a PasswordEncoder bean to encode and decode passwords
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Step 8: Create Signin Request Class

Create a package named request and create SigninRequest.

  • Stores login credentials.
  • Used during authentication requests.
Java
package com.gfg.customauthenticationfailure.request;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

// Lombok annotations for automatically generating getters, setters, and constructors
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SigninRequest {

    // Fields for username and password
    String username;
    String password;
}

Step 9: Create User Controller

Create a package named controller and create UserController.

  • Handles signup requests.
  • Handles signin requests.
  • Authenticates users using username and password.
Java
package com.gfg.customauthenticationfailure.controller;

import com.gfg.customauthenticationfailure.model.User;
import com.gfg.customauthenticationfailure.repository.UserRepository;
import com.gfg.customauthenticationfailure.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import com.gfg.customauthenticationfailure.request.SigninRequest;

@RestController
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    // Handle the /signup endpoint for registering new users
    @PostMapping("/signup")
    public void signUp(@RequestBody User user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        userRepository.save(user);
    }

    @Autowired
    private UserService userService;

    // Handle the /signin endpoint for user authentication
    @PostMapping("/signin")
    public void signIn(@RequestBody SigninRequest signInRequest) throws Exception {
        // Authenticate the user manually
        User user = userService.findByUsername(signInRequest.getUsername());
        if (user != null && user.getPassword().equals(signInRequest.getPassword())) {
            // If the user is found and the password matches, authenticate the user
            Authentication authentication = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } else {
            // If the user is not found or the password doesn't match, throw an exception
            throw new Exception("Invalid username or password");
        }
    }
}

Step 10: Create Main Application Class

Create the Spring Boot main class.

  • Starts the Spring Boot application.
  • Initializes all Spring components.
Java
package com.gfg.customauthenticationfailure;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CustomAuthenticationFailureApplication {

    public static void main(String[] args) {
        SpringApplication.run(CustomAuthenticationFailureApplication.class, args);  // starts the Spring Boot application
        // run the Spring Boot application
    }
  

}

Step 11: Run the Application

Run the Spring Boot application.

  • Application starts on port 8080.
  • Register users using /signup.
  • Authenticate users using /signin.

Application Runs

Comment

Explore