Spring Security
AuthenticationEntryPoint
Java Configuration
Security Customization
XML-Free Configuration

How to define a custom AuthenticationEntryPoint without XML configuration

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Spring Security, an AuthenticationEntryPoint decides what happens when an unauthenticated user tries to access a protected resource. The default behavior is often a redirect to a login page, which is fine for browser-based apps but wrong for JSON APIs that should return a 401 response body.

You do not need XML configuration to customize this. In modern Spring Security, the standard approach is to implement AuthenticationEntryPoint and register it in a SecurityFilterChain bean.

Understand when AuthenticationEntryPoint is used

This hook runs when the request is not authenticated at all. It is not the same as access-denied handling.

  • unauthenticated request to a protected endpoint: AuthenticationEntryPoint
  • authenticated user without enough authority: AccessDeniedHandler

That distinction matters because many "why is my custom entry point not called?" bugs are actually authorization failures, not authentication failures.

Implement a custom entry point

For an API, a common custom behavior is to send JSON instead of redirecting:

java
1import jakarta.servlet.http.HttpServletRequest;
2import jakarta.servlet.http.HttpServletResponse;
3import org.springframework.http.MediaType;
4import org.springframework.security.core.AuthenticationException;
5import org.springframework.security.web.AuthenticationEntryPoint;
6import java.io.IOException;
7
8public class JsonAuthenticationEntryPoint implements AuthenticationEntryPoint {
9
10    @Override
11    public void commence(
12        HttpServletRequest request,
13        HttpServletResponse response,
14        AuthenticationException authException
15    ) throws IOException {
16        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
17        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
18        response.getWriter().write("""
19            {"error":"unauthorized","message":"Authentication is required"}
20            """);
21    }
22}

This gives clients a clear 401 response that is appropriate for API consumers.

Register it with Java configuration

In current Spring Security style, configure security with a SecurityFilterChain bean:

java
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.security.config.annotation.web.builders.HttpSecurity;
4import org.springframework.security.web.SecurityFilterChain;
5
6@Configuration
7public class SecurityConfig {
8
9    @Bean
10    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
11        return http
12            .csrf(csrf -> csrf.disable())
13            .authorizeHttpRequests(auth -> auth
14                .requestMatchers("/public/**").permitAll()
15                .anyRequest().authenticated()
16            )
17            .exceptionHandling(exception -> exception
18                .authenticationEntryPoint(new JsonAuthenticationEntryPoint())
19            )
20            .build();
21    }
22}

That is the central hook: exceptionHandling(...).authenticationEntryPoint(...).

Use it differently for browser apps and APIs

For a browser application, a redirecting entry point may still be the right answer. For example, you might send unauthenticated users to a custom login page.

For APIs, though, redirecting is usually the wrong contract. API clients expect a status code and structured body, not HTML navigation.

If your application has both browser and API endpoints, you may need different security chains or request matchers so each kind of endpoint gets the correct behavior.

Test the behavior explicitly

A small integration test helps verify that the custom entry point is actually wired:

java
1import org.junit.jupiter.api.Test;
2import org.springframework.beans.factory.annotation.Autowired;
3import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
4import org.springframework.boot.test.context.SpringBootTest;
5import org.springframework.test.web.servlet.MockMvc;
6
7import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
8import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
9
10@SpringBootTest
11@AutoConfigureMockMvc
12class SecurityTest {
13
14    @Autowired
15    private MockMvc mockMvc;
16
17    @Test
18    void protectedEndpointReturns401() throws Exception {
19        mockMvc.perform(get("/api/private"))
20            .andExpect(status().isUnauthorized());
21    }
22}

This kind of test catches configuration drift early, especially when security rules evolve.

Common Pitfalls

The most common mistake is expecting AuthenticationEntryPoint to handle authorization failures for already authenticated users. That is the job of an AccessDeniedHandler.

Another issue is returning redirects for API endpoints. That works technically, but it is a poor contract for API clients that expect JSON and status codes.

Developers also sometimes configure a custom entry point but forget that another security chain or default config matches the request first. If the wrong chain wins, your custom entry point never runs.

Finally, avoid copying outdated examples based on XML or older configuration styles unless you are maintaining an older codebase. Modern Spring Security uses bean-based Java configuration as the normal approach.

Summary

  • Implement AuthenticationEntryPoint when you want custom behavior for unauthenticated access.
  • Register it through exceptionHandling(...).authenticationEntryPoint(...) in a SecurityFilterChain.
  • Use JSON 401 responses for APIs instead of login-page redirects.
  • Do not confuse unauthenticated access with authorization failures for authenticated users.
  • Test the response path so you know the intended security chain is actually handling the request.

Course illustration
Course illustration

All Rights Reserved.