π Why Customize Authentication?
Spring Security provides powerful default authentication mechanisms. But real-world applications often need custom logic β such as validating users from a database, LDAP, or a third-party service. Thatβs where a Custom Authentication Provider and UserDetailsService shine.
With this setup, you gain full control over how credentials are verified and user data is retrieved.

π¦ Maven Dependencies
Add the following to your pom.xml:
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-web
π§© Project Structure
com.kscodes.springboot.security.customauth
βββ config/
β βββ SecurityConfig.java
βββ controller/
β βββ AuthController.java
βββ model/
β βββ AppUser.java
βββ security/
β βββ CustomAuthenticationProvider.java
β βββ CustomUserDetailsService.java
βββ CustomAuthApplication.java
π§ Step 1: Create a User Entity
AppUser.java
package com.kscodes.springboot.security.customauth.model;
public class AppUser {
private String username;
private String password;
private String role;
public AppUser(String username, String password, String role) {
this.username = username;
this.password = password;
this.role = role;
}
// Getters and Setters
}
You can later connect this to a database.
π Step 2: Implement UserDetailsService
CustomUserDetailsService.java
package com.kscodes.springboot.security.customauth.security;
import com.kscodes.springboot.security.customauth.model.AppUser;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Service;
import java.util.Collections;
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// Mock user
if (!username.equals("john")) {
throw new UsernameNotFoundException("User not found");
}
AppUser user = new AppUser("john", "pass123", "ROLE_USER");
return new User(
user.getUsername(),
user.getPassword(),
Collections.singleton(new SimpleGrantedAuthority(user.getRole()))
);
}
}
π‘οΈ Step 3: Create a Custom Authentication Provider
CustomAuthenticationProvider.java
package com.kscodes.springboot.security.customauth.security;
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.*;
import org.springframework.stereotype.Component;
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final UserDetailsService userDetailsService;
public CustomAuthenticationProvider(CustomUserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
UserDetails user = userDetailsService.loadUserByUsername(username);
if (!user.getPassword().equals(password)) {
throw new BadCredentialsException("Invalid credentials");
}
return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
}
@Override
public boolean supports(Class> authType) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authType);
}
}
π Step 4: Configure Spring Security
SecurityConfig.java
package com.kscodes.springboot.security.customauth.config;
import com.kscodes.springboot.security.customauth.security.CustomAuthenticationProvider;
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.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
private final CustomAuthenticationProvider authProvider;
public SecurityConfig(CustomAuthenticationProvider authProvider) {
this.authProvider = authProvider;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authenticationProvider(authProvider)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
)
.formLogin(); // or httpBasic()
return http.build();
}
@Bean
public AuthenticationManager authManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}
π Step 5: Authentication Controller
AuthController.java
package com.kscodes.springboot.security.customauth.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AuthController {
@GetMapping("/home")
public String home() {
return "Welcome to the secured home endpoint!";
}
}
π Test It Out
Run the application and test login:
- Visit:
http://localhost:8080/home - Browser will prompt for login
- Enter
john / pass123
β Youβll see the secured content if authentication succeeds using your Custom Authentication Provider and UserDetailsService.
β οΈ Best Practices
- Use
PasswordEncoder(e.g.BCryptPasswordEncoder) instead of plain password comparison. - Fetch users from a real database using repositories.
- Add logging and throttling to prevent brute force attacks.