Extra Login Fields with Spring Security

Last Updated : 24 Jun, 2026

Spring Security provides a built-in authentication mechanism that verifies users using a username and password. However, many real-world applications require additional login fields such as name, department, employee ID, qualification, or security question to implement customized authentication.

  • Create a custom login form with additional fields like Name and Qualification.
  • Capture and process extra login fields using a Custom Authentication Filter.
  • Validate additional fields using a Custom Authentication Provider before authenticating the user.

Implementation of the Extra Login Fields with Spring Security

Follow the steps below to implement extra login fields in Spring Security.

Step 1: Create a Spring Boot Project

Create a new Spring Boot project using Spring Initializr.

Add the following dependencies:

  • Spring Web
  • Spring Security
  • Spring Data JPA
  • Thymeleaf
  • MySQL Driver
  • Lombok
  • Spring Boot DevTools

After creating the project, the folder structure will look similar to the following.

Project Structure

Step 2: Verify the pom.xml File

After project creation, verify that the required dependencies are present in your pom.xml file.

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.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>spring-security-login-extra-fields</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-security-login-extra-fields</name>
    <description>spring-security-login-extra-fields</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</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-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity6</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </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>

Step 3: Configure Application Properties

These properties will be used throughout the application to establish the database connection and store the default application configuration.

spring.application.name=spring-security-login-extra-fields

spring.datasource.url=jdbc:mysql://localhost:3306/example
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.main.allow-circular-references=true
app.user.username=maheshkm5001
app.user.password=Mahesh@123
app.user.name=Mahesh
app.user.qualification=B.Tech

Step 4: Create the User Entity

This entity represents the user information stored in the database. Along with the username and password, it also stores the user's Name and Qualification, which will be used during authentication.

Java
package org.example.springsecurityloginextrafields.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;
    private String password;
    private String name;
    private String qualification;
}

Step 5: Create the User Repository

Create a new package named repository and inside it create a new interface named UserRepository.

Java
package org.example.springsecurityloginextrafields.repository;

import org.example.springsecurityloginextrafields.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}

Step 6: Create the User Service

The service layer acts as an intermediary between the controller and the repository. It is responsible for saving new users and retrieving existing users during authentication.

Java
package org.example.springsecurityloginextrafields.service;

import org.example.springsecurityloginextrafields.model.User;
import org.example.springsecurityloginextrafields.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    // Save user into database
    public void saveUser(User user) {
        userRepository.save(user);
    }

    // Find user by username
    public User findByUsername(String username) {
        return userRepository.findByUsername(username);
    }
}

Step 7: Create CustomUserDetailsService

Spring Security uses the UserDetailsService interface to load user information during authentication. This class retrieves the user from the database and converts it into a Spring Security UserDetails object.

Java
package org.example.springsecurityloginextrafields.service;


import org.example.springsecurityloginextrafields.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;



@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 
    {
        User user = userService.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found");
        }
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
    }
}

Step 8: Configure Spring Security

This class is the central configuration for Spring Security. It performs the following tasks -> Configures authorization rules and Specifies the custom login page and Defines the login processing URL and Redirects users after successful authentication and Registers the custom authentication filter.

Java
package org.example.springsecurityloginextrafields.config;

import org.example.springsecurityloginextrafields.fliter.CustomAuthenticationFilter;

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.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.web.SecurityFilterChain;

import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .requestMatchers("/login", "/perform_login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/perform_login")
                .defaultSuccessUrl("/home", true)
                .permitAll()
                .and()
                .addFilterBefore(customAuthenticationFilter(authenticationManager(http.getSharedObject(AuthenticationConfiguration.class))), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public CustomAuthenticationFilter customAuthenticationFilter(AuthenticationManager authenticationManager) throws Exception {
        CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManager);
        return filter;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}

Step 9: Create CustomAuthenticationProvider

The Authentication Provider is responsible for validating user credentials. In addition to checking the username and password, it also validates the extra login fields such as Name and Qualification. If all values are valid, the user is authenticated successfully; otherwise, authentication fails.

Java
package org.example.springsecurityloginextrafields.config;



import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;




@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    private final UserDetailsService userDetailsService;

    public CustomAuthenticationProvider(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = (String) authentication.getCredentials();

        UserDetails user = userDetailsService.loadUserByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found");
        }

        // Validate extra fields
        HttpServletRequest request = ((HttpServletRequest) authentication.getDetails());
        String name = (String) request.getSession().getAttribute("name");
        String qualification = (String) request.getSession().getAttribute("qualification");

        if (name == null || qualification == null) {
            throw new BadCredentialsException("Name or Qualification is missing");
        }

        // Implement your validation logic for name and qualification
        // For demonstration, we assume they must not be empty
        if (name.isEmpty() || qualification.isEmpty()) {
            throw new BadCredentialsException("Invalid name or qualification");
        }

        return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

Step 10: Create CustomAuthenticationFilter

This filter intercepts every login request before authentication.

Java
package org.example.springsecurityloginextrafields.filter;


import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


import java.io.IOException;

public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String name = request.getParameter("name");
        String qualification = request.getParameter("qualification");

        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        // Store extra fields in a way accessible to AuthenticationProvider
        request.getSession().setAttribute("name", name);
        request.getSession().setAttribute("qualification", qualification);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        super.successfulAuthentication(request, response, chain, authResult);
    }
}

Step 11: Create the Controller

This controller manages User Registration and Registration Form Login Form It saves new users and returns the corresponding Thymeleaf pages.

Java
package org.example.springsecurityloginextrafields.controller;


import org.example.springsecurityloginextrafields.model.User;
import org.example.springsecurityloginextrafields.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;



import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/register")
    public String showRegistrationForm() {
        return "register";
    }

    @PostMapping("/register")
    public String registerUser(@RequestParam("username") String username,
                               @RequestParam("password") String password,
                               @RequestParam("confirmPassword") String confirmPassword,
                               @RequestParam("name") String name,
                               @RequestParam("qualification") String qualification) {

        if (!password.equals(confirmPassword)) {
            // Handle password mismatch
            return "redirect:/register?error=passwordsDoNotMatch";
        }

        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setName(name);
        user.setQualification(qualification);

        userService.saveUser(user);

        return "redirect:/welcome";
    }

    @GetMapping("/login")
    public String showLoginForm() {
        return "login";
    }
}

Step 12: Create Main Class

Open the main class and put the below code. (No change are required)

Java
package org.example.springsecurityloginextrafields;

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

@SpringBootApplication
public class SpringSecurityLoginExtraFieldsApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityLoginExtraFieldsApplication.class, args);
    }

}

Step 13: Create the Registration Page

Create register.html inside the templates folder. The registration page allows users to enter:Username and Password and Confirm Password and Name or Qualification.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Registration Page</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f8f9fa;
        }

        .container {
            margin-top: 50px;
            display: flex;
            justify-content: center;
        }

        .card {
            width: 100%;
            max-width: 500px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            border-radius: 8px;
            background-color: #fff;
        }

        .card-header {
            background-color: #007bff;
            color: #fff;
            border-bottom: none;
            border-radius: 8px 8px 0 0;
            padding: 15px;
            text-align: center;
        }

        .card-body {
            padding: 25px;
        }

        .form-label {
            margin-bottom: 10px;
            font-weight: bold;
        }

        .form-control {
            width: 100%;
            padding: 10px;
            margin-bottom: 20px;
            border: 1px solid #ced4da;
            border-radius: 4px;
            font-size: 16px;
        }

        .btn-primary {
            background-color: #007bff;
            border: none;
            color: #fff;
            padding: 12px;
            font-size: 16px;
            border-radius: 4px;
            cursor: pointer;
            width: 100%;
        }

        .btn-primary:hover {
            background-color: #0056b3;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="card">
        <div class="card-header">
            <h4>Register</h4>
        </div>
        <div class="card-body">
            <form method="post" action="/register">
                <div class="mb-3">
                    <label for="username" class="form-label">Username:</label>
                    <input type="text" class="form-control" id="username" name="username" required>
                </div>
                <div class="mb-3">
                    <label for="password" class="form-label">Password:</label>
                    <input type="password" class="form-control" id="password" name="password" required>
                </div>
                <div class="mb-3">
                    <label for="confirmPassword" class="form-label">Confirm Password:</label>
                    <input type="password" class="form-control" id="confirmPassword" name="confirmPassword" required>
                </div>
                <div class="mb-3">
                    <label for="name" class="form-label">Name:</label>
                    <input type="text" class="form-control" id="name" name="name" required>
                </div>
                <div class="mb-3">
                    <label for="qualification" class="form-label">Qualification:</label>
                    <input type="text" class="form-control" id="qualification" name="qualification" required>
                </div>
                <div class="d-grid">
                    <button type="submit" class="btn btn-primary">Register</button>
                </div>
            </form>
        </div>
    </div>
</div>
</body>
</html>

Step 14: Create the Login Page

Unlike the default Spring Security login page, this page accepts two additional fields - Name and Qualification These values are captured by the custom authentication filter and validated by the custom authentication provider.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Page</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f8f9fa;
        }

        .container {
            margin-top: 50px;
            display: flex;
            justify-content: center;
        }

        .card {
            width: 100%;
            max-width: 500px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            border-radius: 8px;
            background-color: #fff;
        }

        .card-header {
            background-color: #007bff;
            color: #fff;
            border-bottom: none;
            border-radius: 8px 8px 0 0;
            padding: 15px;
            text-align: center;
        }

        .card-body {
            padding: 25px;
        }

        .form-label {
            margin-bottom: 10px;
            font-weight: bold;
        }

        .form-control {
            width: 100%;
            padding: 10px;
            margin-bottom: 20px;
            border: 1px solid #ced4da;
            border-radius: 4px;
            font-size: 16px;
        }

        .btn-primary {
            background-color: #007bff;
            border: none;
            color: #fff;
            padding: 12px;
            font-size: 16px;
            border-radius: 4px;
            cursor: pointer;
            width: 100%;
        }

        .btn-primary:hover {
            background-color: #0056b3;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="card">
        <div class="card-header">
            <h4>Login</h4>
        </div>
        <div class="card-body">
            <form method="post" action="/perform_login">
                <div class="mb-3">
                    <label for="username" class="form-label">Username:</label>
                    <input type="text" class="form-control" id="username" name="username" required>
                </div>
                <div class="mb-3">
                    <label for="password" class="form-label">Password:</label>
                    <input type="password" class="form-control" id="password" name="password" required>
                </div>
                <div class="mb-3">
                    <label for="name" class="form-label">Name:</label>
                    <input type="text" class="form-control" id="name" name="name" required>
                </div>
                <div class="mb-3">
                    <label for="qualification" class="form-label">Qualification:</label>
                    <input type="text" class="form-control" id="qualification" name="qualification" required>
                </div>
                <div class="d-grid">
                    <button type="submit" class="btn btn-primary">Login</button>
                </div>
            </form>
        </div>
    </div>
</div>
</body>
</html>

Step 15: Create the Welcome Page

This page is displayed after successful authentication.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 <h1>Welcome User</h1>

</body>
</html>

Step 16: Run the Application

  • Right Click Project
  • Run 'SpringDisableSecurityDemoApplication'

After successfully completion of the spring project, run it as spring application and once it runs successfully, it starts at port 8080.

Application Runs

Open your browser and hit a below Url.

http://localhost:8080/register

Output:

Below is the Registration page.

registerweb

Enter the username, password, name and qualification for the register and these credentials can save into the database.

Login page:

http://localhost:8080/login

Output:

Below is the Login page.

Login page

Enter the registered username, password, name and qualification. The custom authentication provider will be handle these additional fields during the authentication process.

Welcome page:

Welcome Page
`

Explanation: This project demonstrates how to add the extra fields to the Spring Security login form that allows more customized and secure the authentication processes. By following these steps outlined in this article, we can enhance the Spring Boot application to meet specific authentication requirements.

Comment

Explore