Home Java Custom AuthenticationProvider in Spring Security: DAOs and Custom Providers
Advanced 6 min · July 14, 2026

Custom AuthenticationProvider in Spring Security: DAOs and Custom Providers

Learn to implement custom AuthenticationProvider in Spring Security for non-standard auth flows.

N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Written from production experience, not tutorials.

Follow
Production
production tested
July 15, 2026
last updated
2,398
articles · all by Naren
Before you start⏱ 15-20 min read
  • Basic knowledge of Spring Security
  • Familiarity with dependency injection in Spring
  • Understanding of authentication and authorization concepts
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Use AuthenticationProvider for custom authentication logic like LDAP, legacy systems, or multi-factor auth.
  • Implement the authenticate() and supports() methods.
  • Register the provider in the security configuration.
  • Avoid common mistakes like forgetting to set authentication object details or misusing supports().
  • In production, ensure thread-safety and handle exceptions properly.
✦ Definition~90s read
What is Custom AuthenticationProvider in Spring Security?

A custom AuthenticationProvider is a Spring Security component that implements the AuthenticationProvider interface to perform custom authentication logic, such as validating credentials against an external system or using a non-standard token format.

Think of AuthenticationProvider as a custom lock for your app's front door.
Plain-English First

Think of AuthenticationProvider as a custom lock for your app's front door. Spring Security has standard locks (like username/password), but if you need a fingerprint scanner or a voice recognition system, you build your own lock. The authenticate method checks if the key fits, and supports tells the system which doors this lock works on.

If you've ever worked with Spring Security, you know it handles standard username/password authentication out of the box. But what happens when your boss says, 'We need to authenticate users against our legacy mainframe system' or 'We're adding multi-factor authentication using one-time codes'? That's where the default DaoAuthenticationProvider falls short.

I've seen too many teams try to hack around this by overriding UserDetailsService or stuffing custom logic into filters. That's a recipe for security holes and unmaintainable code. The right tool for the job is a custom AuthenticationProvider.

In this article, I'll show you how to implement a custom AuthenticationProvider from scratch. We'll use a realistic example: authenticating users against a third-party REST API that returns a token. You'll learn the contract, the pitfalls, and what the official docs gloss over.

By the end, you'll have a production-ready provider that you can drop into any Spring Boot application. Let's get our hands dirty.

Understanding the AuthenticationProvider Contract

Before we write any code, you need to understand what Spring Security expects from an AuthenticationProvider. The interface is deceptively simple: two methods. But getting them wrong will cause authentication to silently fail or bypass your custom logic entirely.

The authenticate() method receives an Authentication object (typically a token representing the user's credentials) and must return a fully authenticated Authentication object if successful. If authentication fails, throw an AuthenticationException. If the provider doesn't support the given token, return null — this is critical.

The supports() method tells Spring Security whether this provider can handle a given token class. If you return false, your provider will never be called for that token type. Most implementations check authentication.getClass().isAssignableFrom(UsernamePasswordAuthenticationToken.class). But don't be too narrow — you might want to support custom tokens too.

Here's the gotcha: if multiple providers claim to support the same token class, Spring Security will iterate through them in order. The first one that returns a non-null Authentication wins. If all return null, authentication fails with ProviderNotFoundException. So if your provider returns null for a token it claimed to support, you'll get an error.

AuthenticationProviderExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

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

        // Custom logic: validate against external API
        if ("validUser".equals(username) && "validPass".equals(password)) {
            // Return a fully authenticated token with authorities
            return new UsernamePasswordAuthenticationToken(
                    username,
                    password,
                    List.of(new SimpleGrantedAuthority("ROLE_USER"))
            );
        } else {
            throw new BadCredentialsException("Invalid username or password");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
⚠ Remember the Contract
📊 Production Insight
I've seen providers that return null for invalid credentials instead of throwing an exception. This causes the next provider in the chain to be tried, potentially leaking information about which providers exist.
🎯 Key Takeaway
The AuthenticationProvider contract is simple but strict: authenticate() must return a fully populated Authentication object or throw an exception; supports() must correctly indicate token compatibility.

Registering Your Custom Provider

Creating the provider class is only half the battle. You need to register it with Spring Security's AuthenticationManager. There are two common approaches: using a custom AuthenticationManagerBuilder in a WebSecurityConfigurerAdapter (or its replacement in Spring Security 5.7+), or exposing the provider as a bean and injecting it.

In modern Spring Boot (2.7+), the recommended way is to create a @Configuration class that extends WebSecurityConfigurerAdapter or, even better, use the lambda DSL. Let me show you both.

First, the traditional way with WebSecurityConfigurerAdapter (still works but deprecated in 3.1):

```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomAuthenticationProvider authProvider;

@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authProvider); } } ```

If you're using the new lambda DSL (Spring Security 5.7+), you can do this:

``java @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authenticationProvider(new CustomAuthenticationProvider()) .authorizeHttpRequests(authz -> authz .anyRequest().authenticated() ) .formLogin(); return http.build(); } } ``

Notice I'm creating a new instance of the provider in the lambda DSL. That's fine if the provider is stateless. If it has dependencies, inject them via constructor and create the bean in a @Bean method.

One common mistake I see: developers forget to add @Component to their provider or forget to inject it. The provider simply never gets called, and they waste hours debugging why authentication fails.

SecurityConfig.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authenticationProvider(new CustomAuthenticationProvider())
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin();
        return http.build();
    }
}
🔥Spring Security 5.7+ Changes
📊 Production Insight
When using the lambda DSL, be careful about scoping. If your provider holds state, make it a @Component with singleton scope. Stateless providers are preferred.
🎯 Key Takeaway
Register your custom provider either by injecting it into AuthenticationManagerBuilder or by using the lambda DSL. Ensure the provider is a Spring bean to get dependency injection.

Real-World Example: Token-Based Authentication with External API

Let's build something you'll actually use. Imagine you're integrating with a third-party identity provider that returns a JWT token. The user sends username/password, your provider calls the external API, gets a token, and then sets that token in the security context.

First, let's create a service to call the external API. I'll use RestTemplate for simplicity, but in production you'd use WebClient with proper timeouts.

```java @Service public class ExternalAuthService { private final RestTemplate restTemplate;

public ExternalAuthService() { this.restTemplate = new RestTemplate(); restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); }

public String authenticate(String username, String password) { // Call external API String url = "https://auth.example.com/login"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); Map<String, String> body = Map.of("username", username, "password", password); HttpEntity<Map<String, String>> request = new HttpEntity<>(body, headers);

ResponseEntity<Map> response = restTemplate.postForEntity(url, request, Map.class); if (response.getStatusCode() == HttpStatus.OK) { return response.getBody().get("token").toString(); } else { throw new BadCredentialsException("Authentication failed"); } } } ```

```java @Component public class TokenAuthenticationProvider implements AuthenticationProvider {

private final ExternalAuthService authService;

public TokenAuthenticationProvider(ExternalAuthService authService) { this.authService = authService; }

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

String token = authService.authenticate(username, password);

// Create a custom principal that holds the token UserPrincipal principal = new UserPrincipal(username, token); return new UsernamePasswordAuthenticationToken(principal, null, List.of(new SimpleGrantedAuthority("ROLE_USER"))); }

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

Notice I'm setting the credentials to null in the returned token. This is a security best practice: once authenticated, you don't need to store the password. The token is stored in the principal, which you can retrieve later.

One thing the docs don't tell you: if you set credentials to null, Spring Security will not erase them again (since they're already null). This avoids a second null assignment.

TokenAuthenticationProvider.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class TokenAuthenticationProvider implements AuthenticationProvider {

    private final ExternalAuthService authService;

    public TokenAuthenticationProvider(ExternalAuthService authService) {
        this.authService = authService;
    }

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

        String token = authService.authenticate(username, password);

        UserPrincipal principal = new UserPrincipal(username, token);
        return new UsernamePasswordAuthenticationToken(principal, null, List.of(new SimpleGrantedAuthority("ROLE_USER")));
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
💡Clear Credentials After Authentication
📊 Production Insight
External API calls in authentication need proper error handling. Don't expose internal error details to the client. Use a generic 'Authentication failed' message and log the actual cause.
🎯 Key Takeaway
In a token-based provider, delegate the actual authentication to an external service, then store the token in the principal. Always clear credentials in the returned token.

Chaining Multiple AuthenticationProviders

In many applications, you need to support multiple authentication mechanisms. For example, you might have a legacy system using username/password and a new system using OAuth2 tokens. Spring Security allows you to chain multiple providers.

When you register multiple providers, Spring Security iterates through them in the order they were added. The first provider that returns a non-null Authentication wins. If a provider returns null, the next one is tried. If all return null, authentication fails.

``java @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authenticationProvider(new LdapAuthenticationProvider()) .authenticationProvider(new DatabaseAuthenticationProvider()) .authorizeHttpRequests(authz -> authz .anyRequest().authenticated() ) .formLogin(); return http.build(); } } ``

But be careful: if two providers support the same token type, the order matters. Also, if a provider throws an exception, the chain stops and authentication fails immediately. So if you want fallback behavior, don't throw exceptions for unsupported tokens — return null instead.

I once worked on a project where the team had a provider that threw BadCredentialsException for invalid credentials, but they wanted to fall back to a second provider. They didn't realize that exceptions stop the chain. We had to refactor to return null for tokens that weren't meant for that provider.

MultiProviderConfig.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class MultiProviderConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authenticationProvider(new LdapAuthenticationProvider())
            .authenticationProvider(new DatabaseAuthenticationProvider())
            .authorizeHttpRequests(authz -> authz
                .anyRequest().authenticated()
            )
            .formLogin();
        return http.build();
    }
}
⚠ Exceptions Stop the Chain
📊 Production Insight
Order providers from most specific to most general. For example, put a token-based provider before a username/password provider to avoid unnecessary database calls.
🎯 Key Takeaway
Multiple providers are tried in order; the first non-null response wins. Exceptions stop the chain, so use null returns for fallback scenarios.

What the Official Docs Won't Tell You

I've been using Spring Security since the Acegi days, and I've seen the same mistakes repeated over and over. Here are the things the official documentation glosses over.

1. Thread Safety is Your Responsibility

The official docs mention that AuthenticationProvider instances are shared across threads, but they don't emphasize it enough. If your provider has any mutable state (like a SimpleDateFormat or a non-thread-safe cache), you'll get intermittent failures. I once debugged a production issue where a provider used HashMap without synchronization, causing occasional NullPointerException under load. Always use thread-safe constructs or make your provider stateless.

2. The supports() Method Can Be Tricky

You might think supports() should return true for all token types you can handle. But if you return true for a broad class like Authentication.class, your provider will be called for every authentication request, even those meant for other providers. This can cause performance issues or unexpected behavior. Be as specific as possible.

3. Setting Credentials to Null

Spring Security has a feature that erases credentials after authentication to prevent accidental exposure. But if you set credentials to null in your returned token, it won't try to erase them again. However, if you leave them non-null, Spring Security will erase them, but only if the token is an instance of UsernamePasswordAuthenticationToken. If you use a custom token, you need to handle erasure yourself.

4. The AuthenticationManager is a Singleton

There is only one AuthenticationManager per security filter chain. If you have multiple filter chains (e.g., for different URL patterns), each has its own manager and provider list. This is important when you have different authentication requirements for different parts of your app.

5. ProviderNotFoundException is Silent

If no provider supports a given token, Spring Security throws ProviderNotFoundException. But this exception is often caught and translated to a generic 'Authentication failed' message. This can be confusing because the user might have valid credentials, but the token type is wrong. Always check your supports() methods.

⚠ Thread Safety is Not Optional
📊 Production Insight
I've seen a provider that used a non-thread-safe cache for authentication results. Under load, it returned stale data, causing valid users to be rejected. Use ConcurrentHashMap or a proper caching solution.
🎯 Key Takeaway
Official docs don't emphasize thread safety, the subtleties of supports(), credential erasure, or the singleton nature of AuthenticationManager. Keep these in mind to avoid production issues.

Testing Your Custom AuthenticationProvider

You should never deploy a custom AuthenticationProvider without testing it thoroughly. Here's how I test mine.

First, unit test the provider in isolation. Mock the external dependencies and verify that: - Valid credentials return a non-null Authentication with correct authorities. - Invalid credentials throw the appropriate exception. - Unsupported token types cause the provider to return null.

```java @ExtendWith(MockitoExtension.class) class CustomAuthenticationProviderTest {

@Mock private ExternalAuthService authService;

@InjectMocks private CustomAuthenticationProvider provider;

@Test void testAuthenticateSuccess() { when(authService.authenticate("user", "pass")).thenReturn("token123"); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "pass"); Authentication result = provider.authenticate(token); assertNotNull(result); assertTrue(result.isAuthenticated()); assertEquals("user", result.getName()); assertEquals(1, result.getAuthorities().size()); }

@Test void testAuthenticateFailure() { when(authService.authenticate("user", "wrong")).thenThrow(new BadCredentialsException("Invalid")); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "wrong"); assertThrows(BadCredentialsException.class, () -> provider.authenticate(token)); }

@Test void testSupports() { assertTrue(provider.supports(UsernamePasswordAuthenticationToken.class)); assertFalse(provider.supports(OtherToken.class)); } } ```

Second, integration test with the full Spring context. Use @SpringBootTest and TestRestTemplate to send requests and verify authentication works end-to-end.

```java @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class AuthenticationIntegrationTest {

@Autowired private TestRestTemplate restTemplate;

@Test void testLoginSuccess() { ResponseEntity<String> response = restTemplate.postForEntity("/login", Map.of("username", "user", "password", "pass"), String.class); assertEquals(200, response.getStatusCodeValue()); }

@Test void testLoginFailure() { ResponseEntity<String> response = restTemplate.postForEntity("/login", Map.of("username", "user", "password", "wrong"), String.class); assertEquals(401, response.getStatusCodeValue()); } } ```

Don't forget to test concurrency. Use an executor service to simulate multiple simultaneous authentication requests and ensure no race conditions occur.

CustomAuthenticationProviderTest.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;

@ExtendWith(MockitoExtension.class)
class CustomAuthenticationProviderTest {

    @Mock
    private ExternalAuthService authService;

    @InjectMocks
    private CustomAuthenticationProvider provider;

    @Test
    void testAuthenticateSuccess() {
        when(authService.authenticate("user", "pass")).thenReturn("token123");
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "pass");
        Authentication result = provider.authenticate(token);
        assertNotNull(result);
        assertTrue(result.isAuthenticated());
        assertEquals("user", result.getName());
        assertEquals(1, result.getAuthorities().size());
    }

    @Test
    void testAuthenticateFailure() {
        when(authService.authenticate("user", "wrong")).thenThrow(new BadCredentialsException("Invalid"));
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "wrong");
        assertThrows(BadCredentialsException.class, () -> provider.authenticate(token));
    }

    @Test
    void testSupports() {
        assertTrue(provider.supports(UsernamePasswordAuthenticationToken.class));
        assertFalse(provider.supports(OtherToken.class));
    }
}
💡Test Concurrency
📊 Production Insight
I once found a bug where the provider returned the same Authentication object for concurrent requests, causing shared mutable state. Always create new instances in authenticate().
🎯 Key Takeaway
Unit test the provider with mocks, integration test with the full context, and stress test for concurrency. Never skip testing.
● Production incidentPOST-MORTEMseverity: high

The Midnight Outage: AuthenticationProvider Thread Safety

Symptom
Users intermittently got 403 Forbidden errors during peak hours. The error log showed 'Authentication failed: session expired' even for valid tokens.
Assumption
The developer assumed the issue was with the third-party auth service being slow, so they increased timeouts.
Root cause
The custom AuthenticationProvider had a shared SimpleDateFormat instance that was not thread-safe. Under high concurrency, date parsing corrupted the token validation logic.
Fix
Replaced SimpleDateFormat with DateTimeFormatter (immutable and thread-safe) and added synchronization around the external API call to prevent race conditions on the connection pool.
Key lesson
  • Always ensure AuthenticationProvider implementations are thread-safe; they are called by multiple threads.
  • Avoid mutable shared state; prefer stateless providers or use immutable objects.
  • External API calls in authentication should have proper timeouts and retry mechanisms.
  • Test under load with concurrent requests to uncover race conditions.
  • Log authentication failures with enough context to debug, but never log credentials.
Production debug guideSymptom to Action4 entries
Symptom · 01
Authentication always fails with 'Bad credentials' even with correct credentials.
Fix
Check if supports() returns true for the token class. Also verify that the authenticate() method throws the correct exception type (e.g., BadCredentialsException).
Symptom · 02
Provider is never invoked; authentication passes through default provider.
Fix
Ensure the custom provider is registered in the security configuration. Use AuthenticationManagerBuilder.authenticationProvider() or define a bean in a @Configuration class.
Symptom · 03
Intermittent authentication failures under load.
Fix
Check for thread-safety issues. Look for shared mutable objects like SimpleDateFormat, Calendar, or non-thread-safe collections. Also verify external service timeouts.
Symptom · 04
Authentication succeeds but user details are missing (e.g., roles).
Fix
In the authenticate() method, ensure you set the GrantedAuthority list correctly on the UsernamePasswordAuthenticationToken. Also verify that the UserDetails object is populated.
★ Quick Debug Cheat SheetCommon symptoms and immediate actions for custom AuthenticationProvider issues.
Provider not called
Immediate action
Check if provider bean is defined and supports() returns true
Commands
curl -v https://your-api/login -d 'username=test&password=test'
Check logs for 'Authenticated user' or 'Authentication failed'
Fix now
Add @Component to provider class and ensure it's injected in SecurityConfig
BadCredentialsException for valid input+
Immediate action
Enable DEBUG logging for org.springframework.security
Commands
logging.level.org.springframework.security=DEBUG in application.properties
Check authenticate() method logic and exception handling
Fix now
Verify that the authentication result is returned, not null
NullPointerException in authenticate()+
Immediate action
Check if authentication.getPrincipal() or getCredentials() are null
Commands
Add null checks at the start of authenticate()
Ensure the token class is supported
Fix now
Return null if token is not supported; throw AuthenticationException if null credentials
FeatureAuthenticationProviderUserDetailsService
PurposePerforms authentication logicLoads user details from a data source
Return typeAuthentication objectUserDetails object
Exception handlingThrows AuthenticationException on failureThrows UsernameNotFoundException if user not found
Typical usageCustom auth flows (LDAP, API, etc.)Database-backed authentication
⚙ Quick Reference
5 commands from this guide
FileCommand / CodePurpose
AuthenticationProviderExample.java@ComponentUnderstanding the AuthenticationProvider Contract
SecurityConfig.java@ConfigurationRegistering Your Custom Provider
TokenAuthenticationProvider.java@ComponentReal-World Example
MultiProviderConfig.java@ConfigurationChaining Multiple AuthenticationProviders
CustomAuthenticationProviderTest.java@ExtendWith(MockitoExtension.class)Testing Your Custom AuthenticationProvider

Key takeaways

1
Implement AuthenticationProvider for custom authentication logic beyond username/password.
2
Follow the contract
return non-null Authentication on success, throw exception on failure, return null for unsupported tokens.
3
Ensure thread safety
providers are singletons; avoid mutable state.
4
Register the provider in security configuration; otherwise it won't be used.
5
Test thoroughly
unit tests, integration tests, and concurrency tests.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
Explain the AuthenticationProvider interface and its two methods.
Q02SENIOR
How would you implement a custom AuthenticationProvider that authenticat...
Q03SENIOR
What are the thread-safety considerations for a custom AuthenticationPro...
Q01 of 03JUNIOR

Explain the AuthenticationProvider interface and its two methods.

ANSWER
AuthenticationProvider has authenticate(Authentication) and supports(Class<?>). authenticate() performs authentication and returns a fully populated Authentication object on success, or throws AuthenticationException on failure. supports() indicates whether the provider can handle a given token class. If supports() returns false, the provider will not be called for that token.
FAQ · 3 QUESTIONS

Frequently Asked Questions

01
What is the difference between AuthenticationProvider and UserDetailsService?
02
Can I have multiple AuthenticationProviders in the same application?
03
How do I pass custom parameters (like tenant ID) to the AuthenticationProvider?
N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Written from production experience, not tutorials.

Follow
Verified
production tested
July 15, 2026
last updated
2,398
articles · all by Naren
🔥

That's Spring Security. Mark it forged?

6 min read · try the examples if you haven't

Previous
Spring Security Basic Authentication Configuration and Best Practices
12 / 31 · Spring Security
Next
How to Manually Authenticate a User in Spring Security