Popular Searches
Popular Course Categories
Popular Courses

Configuring Security Filter Chains

Configuring Security Filter Chains

Spring Security and Secure REST APIs

Configuring Security Filter Chains in Spring Security

Course: Advanced Java Training

Topic: Configuring Security Filter Chains

Course Link: Advanced Java Training Course

Demo Link: Register for a Free Course Demo

Website: JustAcademy


1. Introduction to Security Filter Chains

Spring Security is a powerful framework used to secure Java applications, especially Spring Boot web applications and REST APIs. It provides authentication, authorization, session management, protection against common web attacks, and request filtering.

A Security Filter Chain is a sequence of servlet filters that process incoming HTTP requests before they reach the application's controller. These filters inspect requests, identify users, validate authentication credentials, check permissions, and apply security rules.

In modern Spring Security applications, security rules are commonly configured using a SecurityFilterChain bean and the HttpSecurity API.

Why Are Security Filter Chains Important?

  • They protect application endpoints from unauthorized access.
  • They determine how users authenticate.
  • They define which URLs require authentication and which are publicly accessible.
  • They help configure login, logout, sessions, and exception handling.
  • They allow different security policies for web pages, REST APIs, and administrative endpoints.
  • They provide a centralized approach to application security.

2. Understanding the Spring Security Architecture

Spring Security uses a collection of filters to process incoming requests. The servlet container passes an HTTP request through Spring Security's filter infrastructure before the request reaches a controller.

Important Components

Component Description
SecurityFilterChain Defines a sequence of security filters and the requests to which the chain applies.
HttpSecurity Provides a configuration API for authentication, authorization, CSRF, sessions, and other security features.
FilterChainProxy Spring Security's central filter proxy that delegates requests to a matching security filter chain.
DelegatingFilterProxy Connects the servlet container's filter mechanism to a Spring-managed filter bean, commonly the Spring Security filter proxy.
Authentication Represents authentication information, including the principal and granted authorities.
SecurityContextHolder Provides access to the current security context for the executing request or thread.
AuthorizationFilter Enforces request authorization rules based on the configured security policies.

3. How a Security Filter Chain Works

When a client sends an HTTP request, the request passes through the servlet filter infrastructure. Spring Security selects the first matching SecurityFilterChain and executes its configured filters.

Request Processing Flow

  1. The client sends an HTTP request to the application.
  2. The servlet container invokes the registered security filter infrastructure.
  3. FilterChainProxy checks the configured security filter chains in order.
  4. The first chain whose request matcher matches the request is selected.
  5. The filters in that chain perform relevant security operations.
  6. Authentication mechanisms validate credentials when authentication is required.
  7. Authorization rules determine whether the authenticated user can access the requested resource.
  8. If access is permitted, the request continues to the controller; otherwise, Spring Security returns or initiates the appropriate denial or authentication response.

Important: Spring Security generally uses the first matching filter chain, not every matching chain. Within that chain, the individual filters execute according to their configured order.

4. Creating a Basic Security Filter Chain

In modern Spring Security configuration, developers typically declare a SecurityFilterChain bean instead of extending the deprecated WebSecurityConfigurerAdapter class.

Step 1: Add the Spring Security Dependency

For a Maven-based Spring Boot project, add the Spring Security starter to your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Use a Spring Boot version compatible with your project and manage dependency versions through the Spring Boot parent or dependency management configuration.

Step 2: Create a Security Configuration Class

package com.example.security;

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.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(
            HttpSecurity http) throws Exception {

        http
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/", "/public/**").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form.permitAll())
            .logout(logout -> logout.permitAll());

        return http.build();
    }
}

Explanation of the Configuration

  • @Configuration marks the class as a Spring configuration class.
  • @Bean registers the configured filter chain in the Spring application context.
  • HttpSecurity provides methods for defining web security policies.
  • requestMatchers("/", "/public/**").permitAll() allows unauthenticated access to the specified public paths.
  • requestMatchers("/admin/**").hasRole("ADMIN") restricts matching paths to users with the ROLE_ADMIN authority.
  • anyRequest().authenticated() requires authentication for all remaining requests.
  • formLogin() enables form-based login.
  • logout() configures logout support.
  • http.build() builds the configured security filter chain.

Note: Matcher rules are evaluated in declaration order. More specific rules should generally appear before broad rules such as anyRequest().

5. Configuring URL-Based Authorization

URL-based authorization determines which users can access different application resources. Spring Security provides methods such as permitAll(), authenticated(), hasRole(), and hasAuthority().

Method Purpose Example
permitAll() Allows access without authentication. /public/**
authenticated() Requires an authenticated user. /profile
hasRole("ADMIN") Requires the role authority ROLE_ADMIN. /admin/**
hasAuthority("REPORT_READ") Requires an exact granted authority. /reports/**
denyAll() Denies access to all users. Disabled endpoint

Example: Role-Based Authorization

@Bean
public SecurityFilterChain securityFilterChain(
        HttpSecurity http) throws Exception {

    http.authorizeHttpRequests(authorize -> authorize
        .requestMatchers("/login", "/register", "/css/**")
            .permitAll()
        .requestMatchers("/admin/**")
            .hasRole("ADMIN")
        .requestMatchers("/manager/**")
            .hasAnyRole("ADMIN", "MANAGER")
        .requestMatchers("/reports/**")
            .hasAuthority("REPORT_READ")
        .anyRequest()
            .authenticated()
    );

    return http.build();
}

This configuration permits access to login, registration, and CSS resources, restricts administrative paths to administrators, and requires a specific authority for report access.

6. Configuring Multiple Security Filter Chains

Large applications may expose both browser-based pages and REST APIs. These resources often require different authentication mechanisms. Spring Security supports multiple SecurityFilterChain beans, each with its own request matcher, authorization rules, and filters.

For example, a REST API might use HTTP Basic authentication while a browser interface uses form login. Each request should be routed to the appropriate chain.

Example: Separate API and Web Chains

package com.example.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class MultiSecurityConfig {

    @Bean
    @Order(1)
    public SecurityFilterChain apiSecurityFilterChain(
            HttpSecurity http) throws Exception {

        http
            .securityMatcher("/api/**")
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/api/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .httpBasic(Customizer.withDefaults())
            .csrf(csrf -> csrf.disable());

        return http.build();
    }

    @Bean
    @Order(2)
    public SecurityFilterChain webSecurityFilterChain(
            HttpSecurity http) throws Exception {

        http
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/", "/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(Customizer.withDefaults());

        return http.build();
    }
}

How Multiple Chains Work

  • @Order(1) gives the API chain higher precedence than the chain with @Order(2).
  • securityMatcher("/api/**") determines which requests are handled by the API chain.
  • The API chain uses HTTP Basic authentication in this example.
  • The web chain handles requests that were not matched by the API chain.
  • Each request is handled by the first matching chain; the chains are not merged together.

Security warning: Disabling CSRF is appropriate only when the API's authentication and deployment model make it safe, such as certain stateless APIs using bearer tokens that are not automatically attached by browsers. HTTP Basic credentials can be sent automatically by browsers, so disabling CSRF requires careful threat analysis. Do not disable CSRF indiscriminately.

7. Understanding securityMatcher() and requestMatchers()

These methods serve different purposes and should not be confused.

Method Purpose Example
securityMatcher() Determines whether an entire security filter chain applies to a request. securityMatcher("/api/**")
requestMatchers() Defines authorization rules inside the selected chain. requestMatchers("/api/admin/**").hasRole("ADMIN")

If no configured chain matches a request, that request may not receive the protections expected from the configured chains. Always consider whether a fallback chain is needed to secure unmatched routes.

8. Configuring Authentication in a Filter Chain

Authentication verifies the identity of a user or client. Spring Security supports multiple authentication methods, including form login, HTTP Basic, OAuth 2.0 login, and resource-server bearer tokens.

Form-Based Authentication

@Bean
public SecurityFilterChain webSecurityFilterChain(
        HttpSecurity http) throws Exception {

    http
        .authorizeHttpRequests(authorize -> authorize
            .requestMatchers("/login", "/register").permitAll()
            .anyRequest().authenticated()
        )
        .formLogin(form -> form
            .loginPage("/login")
            .permitAll()
        )
        .logout(logout -> logout.permitAll());

    return http.build();
}

A custom login page must be implemented by the application and mapped to the configured path. The application must also provide an appropriate user-loading and authentication mechanism.

HTTP Basic Authentication

http
    .authorizeHttpRequests(authorize -> authorize
        .anyRequest().authenticated()
    )
    .httpBasic(Customizer.withDefaults());

HTTP Basic authentication sends credentials with requests using the Authorization header. Use HTTPS in production to protect credentials in transit, and consider whether a different authentication mechanism is more appropriate for your application.

9. Configuring CSRF Protection

Cross-Site Request Forgery (CSRF) is an attack in which a malicious website tricks a user's browser into sending an unwanted request to another website where the user is authenticated.

Spring Security enables CSRF protection by default for typical servlet-based web applications. This protection is particularly important when authentication relies on cookies or sessions automatically sent by the browser.

Default CSRF Protection

@Bean
public SecurityFilterChain securityFilterChain(
        HttpSecurity http) throws Exception {

    http
        .authorizeHttpRequests(authorize -> authorize
            .anyRequest().authenticated()
        )
        .formLogin(Customizer.withDefaults());

    return http.build();
}

In this configuration, CSRF protection remains enabled. State-changing requests such as POST, PUT, PATCH, and DELETE generally need a valid CSRF token when the configured CSRF protection applies.

When Should CSRF Be Disabled?

CSRF protection may be disabled for a particular chain when the application has a carefully designed security model that does not rely on browser-automatically-sent credentials and does not have the same CSRF exposure. Evaluate token storage, cookies, browser behavior, and cross-origin access before changing this setting.

10. Session Management in Security Filter Chains

Session management controls how an application creates and maintains authenticated user sessions. Spring Security supports session fixation protection, concurrent session controls, and different session creation policies.

Example: Stateless API Configuration

import org.springframework.security.config.http.SessionCreationPolicy;

http
    .sessionManagement(session -> session
        .sessionCreationPolicy(
            SessionCreationPolicy.STATELESS
        )
    );

SessionCreationPolicy.STATELESS tells Spring Security not to create or use an HTTP session to obtain the security context for each request. It is commonly used for APIs that authenticate each request using a token.

Policy Description
ALWAYS Always create an HTTP session.
IF_REQUIRED Create a session when required.
NEVER Do not create a session, but an existing session may be used.
STATELESS Do not create a session or use one to obtain the security context.

11. Adding Custom Filters

Sometimes applications need additional request processing, such as custom token validation or request auditing. Spring Security allows a custom filter to be placed relative to known security filters.

Example: Custom Request Filter

import java.io.IOException;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import org.springframework.web.filter.OncePerRequestFilter;

public class RequestAuditFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain)
            throws ServletException, IOException {

        System.out.println(
            "Request received: " + request.getMethod()
                + " " + request.getRequestURI()
        );

        filterChain.doFilter(request, response);
    }
}

Registering the Custom Filter

@Bean
public SecurityFilterChain securityFilterChain(
        HttpSecurity http) throws Exception {

    http
        .addFilterBefore(
            new RequestAuditFilter(),
            org.springframework.security.web.authentication
                .UsernamePasswordAuthenticationFilter.class
        )
        .authorizeHttpRequests(authorize -> authorize
            .anyRequest().authenticated()
        )
        .formLogin(Customizer.withDefaults());

    return http.build();
}

The example demonstrates filter placement. In a real application, use a suitable logging framework instead of printing to standard output. If the custom filter is also registered as a servlet-container filter, ensure it is not unintentionally executed twice. For authentication filters, define the authentication, error handling, and security-context behavior carefully.

12. Exception Handling in Security Filter Chains

Spring Security provides mechanisms to handle authentication failures and authorization denials. The appropriate response depends on whether the client is using a browser-based application or an API.

  • Authentication entry point: Determines what happens when an unauthenticated user requests a protected resource.
  • Access denied handler: Handles requests where the user is authenticated but lacks the required permission.
  • Login failure handler: Defines behavior after unsuccessful form authentication.
  • Logout success handler: Defines behavior after a successful logout.

Example: Custom Access Denied Page

http
    .authorizeHttpRequests(authorize -> authorize
        .requestMatchers("/admin/**").hasRole("ADMIN")
        .anyRequest().authenticated()
    )
    .exceptionHandling(exception -> exception
        .accessDeniedPage("/access-denied")
    )
    .formLogin(Customizer.withDefaults());

The application must provide a controller or view for /access-denied. For a REST API, a structured HTTP 403 response is often more suitable than redirecting to an HTML page.

13. Testing Security Filter Chain Configuration

Testing verifies that public routes, protected routes, roles, and authentication mechanisms behave as expected. Spring Security provides testing support through MockMvc and the spring-security-test dependency.

Example: MockMvc Security Tests

import static org.springframework.test.web.servlet.request
    .MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result
    .MockMvcResultMatchers.status;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet
    .AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

@SpringBootTest
@AutoConfigureMockMvc
class SecurityConfigTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void publicEndpointIsAccessible() throws Exception {
        mockMvc.perform(get("/public/info"))
            .andExpect(status().isOk());
    }

    @Test
    void protectedEndpointRequiresAuthentication()
            throws Exception {
        mockMvc.perform(get("/profile"))
            .andExpect(status().isUnauthorized());
    }
}

Testing note: The expected response depends on the configured authentication mechanism. Form login commonly redirects unauthenticated browser requests to a login page, producing a 3xx response, whereas HTTP Basic or bearer-token APIs commonly return 401. The example assumes the relevant endpoints exist and the configuration is set up to produce the indicated responses. Add spring-security-test to the test dependencies when using Spring Security's test support.

Additional Testing Scenarios

  • Verify that public endpoints work without login.
  • Verify that protected endpoints reject anonymous users.
  • Verify that users with the correct role can access restricted endpoints.
  • Verify that users without the required role receive an access-denied response.
  • Test CSRF token requirements for state-changing requests.
  • Test the behavior of each security chain and requests that do not match a specialized chain.
  • Verify logout behavior and session invalidation where applicable.

14. Common Security Filter Chain Errors and Solutions

Problem Possible Cause Solution
Public page redirects to login The public path is missing from the authorization rules or does not match the actual request. Check the path and add an appropriate permitAll() rule.
Admin endpoint returns 403 The user lacks the required role or authority. Check granted authorities and the role prefix used by hasRole().
API returns 401 Authentication credentials are missing or invalid. Check the Authorization header and authentication configuration.
API request redirects to login The request may be matched by a browser-oriented chain. Review chain ordering and request matchers.
CSRF token error A required CSRF token is missing or invalid. Include a valid token or reassess CSRF configuration based on the application's threat model.
Custom filter executes twice The filter may be registered with both the servlet container and Spring Security. Review filter bean registration and servlet filter registration.
Request receives unexpected security behavior A higher-priority chain matches first or no intended chain matches. Review @Order, securityMatcher(), and fallback-chain coverage.

15. Security Filter Chain Best Practices

  • Use the modern SecurityFilterChain bean configuration style.
  • Keep security rules explicit and easy to review.
  • Place specific authorization matchers before broad rules.
  • Use multiple chains only when the application genuinely needs different security policies.
  • Order specialized chains before general fallback chains.
  • Ensure all sensitive endpoints are covered by an appropriate security chain.
  • Use HTTPS in production.
  • Keep CSRF protection enabled for browser-based session authentication unless a careful security assessment supports a different design.
  • Prefer established Spring Security authentication mechanisms over custom authentication implementations.
  • Store passwords using a suitable password encoder; never store plaintext passwords.
  • Use least-privilege roles and authorities.
  • Test both successful and denied requests.
  • Avoid logging passwords, tokens, session identifiers, or other sensitive credentials.
  • Keep Spring Boot and Spring Security dependencies updated.

16. Practical Example: Securing an Employee Management Application

Suppose an employee management application contains public information, employee profiles, and administrator-only operations. A security filter chain can enforce the following access policy:

Endpoint Access Rule
/ Public access
/public/** Public access
/employee/** Authenticated users
/admin/** Users with the ADMIN role
/reports/** Users with the REPORT_READ authority

Example Configuration

@Bean
public SecurityFilterChain employeeSecurityFilterChain(
        HttpSecurity http) throws Exception {

    http
        .authorizeHttpRequests(authorize -> authorize
            .requestMatchers("/", "/public/**").permitAll()
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .requestMatchers("/reports/**")
                .hasAuthority("REPORT_READ")
            .requestMatchers("/employee/**").authenticated()
            .anyRequest().denyAll()
        )
        .formLogin(Customizer.withDefaults())
        .logout(Customizer.withDefaults());

    return http.build();
}

This configuration follows a deny-by-default approach for unmatched routes within this chain. The application must still ensure that the chain itself matches the intended requests and that user roles and authorities are correctly assigned.

17. Hands-On Practice Exercises

  1. Create a Spring Boot project with Spring Security enabled.
  2. Configure a SecurityFilterChain bean using HttpSecurity.
  3. Allow public access to a home page and a registration endpoint.
  4. Require authentication for an employee profile page.
  5. Restrict administrator URLs to users with the ADMIN role.
  6. Configure form-based login and logout.
  7. Create a separate API chain for /api/**.
  8. Test public and protected endpoints using MockMvc or an API client.
  9. Verify that users without appropriate permissions cannot access restricted endpoints.
  10. Document the authorization rules and explain why each endpoint is public or protected.

18. Interview Questions and Answers

Q1. What is a SecurityFilterChain in Spring Security?

Answer: It defines the security filters and request-matching conditions that apply to a set of HTTP requests. It is commonly configured as a Spring bean using HttpSecurity.

Q2. What is the purpose of HttpSecurity?

Answer: HttpSecurity provides a fluent API for configuring authentication, authorization, CSRF protection, session management, exception handling, and other HTTP security features.

Q3. What is the difference between securityMatcher() and requestMatchers()?

Answer: securityMatcher() determines whether an entire filter chain applies to a request. requestMatchers() defines authorization rules within that chain.

Q4. Can an application have multiple SecurityFilterChain beans?

Answer: Yes. Multiple chains can apply different security policies to different request groups, such as REST APIs and browser-based pages.

Q5. How does Spring Security choose a filter chain?

Answer: It evaluates configured chains in order and selects the first chain whose security matcher matches the request.

Q6. Why is @Order important?

Answer: It helps determine chain evaluation order. More specialized chains should generally precede general-purpose chains that might otherwise match the same requests.

Q7. What is the difference between authentication and authorization?

Answer: Authentication establishes who the user is. Authorization determines whether that user has permission to perform an operation or access a resource.

Q8. What is CSRF protection?

Answer: CSRF protection helps prevent unauthorized state-changing requests initiated through a user's authenticated browser. It is particularly important for cookie- or session-based authentication.

Q9. When is SessionCreationPolicy.STATELESS used?

Answer: It is used when each request should be authenticated independently rather than relying on an HTTP session to retrieve the security context, as in many token-based APIs.

Q10. Why might a user receive HTTP 403?

Answer: The user may be authenticated but lack the role or authority required for the resource. Other security checks can also deny access, so the exact reason should be investigated.

Q11. What happens if no security filter chain matches a request?

Answer: The request may not receive the expected Spring Security protections. A general fallback chain is commonly configured to cover requests not handled by specialized chains.

Q12. How can a custom filter be added?

Answer: A filter can be inserted using methods such as addFilterBefore() or addFilterAfter(). Its placement and behavior should be chosen carefully to avoid bypassing or duplicating security operations.

19. Quick Revision Notes

  • SecurityFilterChain defines a sequence of security filters for matching requests.
  • HttpSecurity is the main API for configuring HTTP security.
  • FilterChainProxy selects the first matching chain.
  • securityMatcher() selects requests for a chain.
  • requestMatchers() defines authorization rules inside the chain.
  • permitAll() allows access without authentication.
  • authenticated() requires authentication.
  • hasRole() checks for a role, conventionally using the ROLE_ prefix.
  • hasAuthority() checks for an exact authority name.
  • Multiple chains support different security policies for different request groups.
  • CSRF protection should be configured according to the application's authentication model.
  • Automated tests help confirm that security rules work as intended.

20. Conclusion

Configuring security filter chains is a fundamental skill for developing secure Spring Boot applications. By understanding how Spring Security selects a chain, defining authorization rules, configuring authentication, managing sessions, and testing protected endpoints, developers can build applications with clear and maintainable security policies.

For further learning, explore the Advanced Java Training Course at JustAcademy. You can also register for a course demo to learn more about the training options.

Visit the JustAcademy website for additional courses and learning resources.

Previous Next
whatsapp