# Why RequestHeaderAuthenticationFilter is not registered as part of Spring Security Filter Chain

# Background

While I was writing for another blog post, I realize something interesting about `RequestHeaderAuthenticationFilter` where it isn't registered as part of the `SecurityFilterChain`. I thought this post should come first, to provide some sort of background knowledge.

Imagine the following configuration

```java
@EnableWebSecurity(debug = true)
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfig {
    @Bean
    public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter(AuthenticationManager authenticationManager) {
        RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter = new RequestHeaderAuthenticationFilter();
        requestHeaderAuthenticationFilter.setPrincipalRequestHeader("X-User");
        requestHeaderAuthenticationFilter.setExceptionIfHeaderMissing(true);
        requestHeaderAuthenticationFilter.setAuthenticationManager(authenticationManager);

        return requestHeaderAuthenticationFilter;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
            .build();
    }

}
```

When a request is sent to the server, the following `SecurityFilterChain` will be logged out

> it is logged because I've set `debug = true` on `@EnableWebSecurity`

```plaintext
Security filter chain: [
  DisableEncodeUrlFilter
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  CsrfFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
]
```

Did you notice what was not inside the `SecurityFilterChain`?

For me, it wasn't immediately obvious as I was expecting to see `RequestHeaderAuthenticationFilter` as part of the `SecurityFilterChain` especially when it is being mentioned in the [documentation](https://docs.spring.io/spring-security/reference/5.8/servlet/architecture.html#servlet-security-filters).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1683392888102/e6bd8449-524d-437b-a16e-19af818d0904.png align="center")

> RequestHeaderAuthenticationFilter is a sub-class of AbstractPreAuthenticatedProcessingFilter

# Understanding

So what happens? Why didn't it get registered as part of `SecurityFilterChain`?

## RequestHeaderAuthenticationFilter

To understand that, we need to first look at the implementation of `RequestHeaderAuthenticationFilter`.

```java
public class RequestHeaderAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {}

public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware {}

public abstract class GenericFilterBean implements Filter ... {}
```

What the above shows us is that `RequestHeaderAuthenticationFilter` is essentially a (Servlet) `Filter`, and the [documentation](https://docs.spring.io/spring-boot/docs/2.7.x/reference/htmlsingle/#web.servlet.embedded-container.servlets-filters-listeners.beans) states

> Any `Servlet`, `Filter`, or servlet `*Listener` instance that is a Spring bean is registered with the embedded container.

This means to say, if we look at the registered filters, we should be able to find `RequestHeaderAuthenticationFilter`.

Let's do that, and see if that's true by listing down all the registered filters which we can do by turning on the log to `debug` in `application.yaml`.

```yaml
logging:
  level:
    org:
      springframework:
        security: TRACE
        # this will display Mapping filters logs
        boot:
          web:
            servlet:
              ServletContextInitializerBeans: DEBUG
```

## Servlet Filter

When the application is started, the mapping filters will be shown

```powershell
2023-05-25 23:39:19.113 DEBUG 26544 --- [  restartedMain] o.s.b.w.s.ServletContextInitializerBeans : Mapping filters: springSecurityFilterChain urls=[/*] order=-100, filterRegistrationBean urls=[/*] order=2147483647, characterEncodingFilter urls=[/*] order=-2147483648, formContentFilter urls=[/*] order=-9900, requestContextFilter urls=[/*] order=-105, requestHeaderAuthenticationFilter urls=[/*] order=2147483647
```

We can see that it is indeed registered as part of the (Servlet) `Filter`.

## Behavior

What does this mean? Should I be concerned? In my own opinion, yes, you should and I will explain why.

### Default

First, let's see what's the default behavior by updating the current `SecurityFilterChain` to the following

```java
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        // added this
        .authorizeHttpRequests(authz -> authz.anyRequest().authenticated())
        .build();
}
```

The new line means that any request to the server must come from an authenticated user. Once we update it, restart the application, and make an HTTP request to the server.

```bash
curl localhost:8080
```

You will encounter the following exception

```powershell
2023-05-23 23:33:26.515  INFO 20680 --- [nio-8080-exec-2] Spring Security Debugger                 : 

************************************************************

Request received for GET '/filters':

org.apache.catalina.connector.RequestFacade@5085c222

servletPath:/filters
pathInfo:null
headers:
host: localhost:8080
user-agent: curl/8.0.1
accept: */*


Security filter chain: [
  DisableEncodeUrlFilter
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  CsrfFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  AuthorizationFilter
]


************************************************************


2023-05-23 23:33:26.520 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@50e12d12, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@c92f53f, org.springframework.security.web.context.SecurityContextPersistenceFilter@1f79d63b, org.springframework.security.web.header.HeaderWriterFilter@30aa5e7d, org.springframework.security.web.csrf.CsrfFilter@5534815, org.springframework.security.web.authentication.logout.LogoutFilter@2c8c013d, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@3e37cacf, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@2680de6e, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@7ed6cc37, org.springframework.security.web.session.SessionManagementFilter@df1f38e, org.springframework.security.web.access.ExceptionTranslationFilter@48bae627, org.springframework.security.web.access.intercept.AuthorizationFilter@54410ddc]] (1/1)
2023-05-23 23:33:26.522 DEBUG 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Securing GET /filters
2023-05-23 23:33:26.522 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking DisableEncodeUrlFilter (1/12)
2023-05-23 23:33:26.523 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking WebAsyncManagerIntegrationFilter (2/12)
2023-05-23 23:33:26.524 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking SecurityContextPersistenceFilter (3/12)
2023-05-23 23:33:26.524 TRACE 20680 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2023-05-23 23:33:26.524 TRACE 20680 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : Created SecurityContextImpl [Null authentication]
2023-05-23 23:33:26.527 DEBUG 20680 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2023-05-23 23:33:26.529 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking HeaderWriterFilter (4/12)
2023-05-23 23:33:26.530 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking CsrfFilter (5/12)
2023-05-23 23:33:26.531 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.csrf.CsrfFilter         : Did not protect against CSRF since request did not match CsrfNotRequired [TRACE, HEAD, GET, OPTIONS]
2023-05-23 23:33:26.533 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking LogoutFilter (6/12)
2023-05-23 23:33:26.567 TRACE 20680 --- [nio-8080-exec-2] o.s.s.w.a.logout.LogoutFilter            : Did not match request to Ant [pattern='/logout', POST]
2023-05-23 23:33:26.573 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking RequestCacheAwareFilter (7/12)
2023-05-23 23:33:26.603 TRACE 20680 --- [nio-8080-exec-2] o.s.s.w.s.HttpSessionRequestCache        : No saved request
2023-05-23 23:33:26.612 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking SecurityContextHolderAwareRequestFilter (8/12)
2023-05-23 23:33:26.619 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking AnonymousAuthenticationFilter (9/12)
2023-05-23 23:33:26.621 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking SessionManagementFilter (10/12)
2023-05-23 23:33:26.622 TRACE 20680 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
2023-05-23 23:33:26.625 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking ExceptionTranslationFilter (11/12)
2023-05-23 23:33:26.628 TRACE 20680 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Invoking AuthorizationFilter (12/12)
2023-05-23 23:33:26.630 TRACE 20680 --- [nio-8080-exec-2] estMatcherDelegatingAuthorizationManager : Authorizing SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@209a3372]
2023-05-23 23:33:26.637 TRACE 20680 --- [nio-8080-exec-2] estMatcherDelegatingAuthorizationManager : Checking authorization on SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@209a3372] using org.springframework.security.authorization.AuthenticatedAuthorizationManager@1f83758
2023-05-23 23:33:26.653 TRACE 20680 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter     : Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied

org.springframework.security.access.AccessDeniedException: Access Denied
        at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:98) ~[spring-security-web-5.8.3.jar:5.8.3]
```

> I enable TRACE log for org.springframework.security so that it shows all the logs

But... what about my `RequestHeaderAuthenticationFilter` that supposed to authenticate my user via `X-User` header? Why is that not being triggered?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686153116970/a8e9b341-3bb8-4c6a-be04-2d10de7ab360.png align="center")

That's because based on the order of the `SecurityFilterChain`, `AnonymousAuthenticationFilter` will get processed first and throws `Access Denied` exception thus it will not reach the servlet `Filter` which is where `RequestHeaderAuthenticationFilter` is registered on.

### AnonymousAuthenticationFilter

What if we disable `AnonymousAuthenticationFilter`?

```java
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
    return http
        .anonymous(AbstractHttpConfigurer::disable)
        .authorizeHttpRequests(authz -> authz.anyRequest().authenticated())
        .build();
}
```

In that case, you will encounter the following

```powershell
2023-05-25 22:10:48.429  INFO 29080 --- [nio-8080-exec-1] Spring Security Debugger                 : 

************************************************************

Request received for GET '/filters':

org.apache.catalina.connector.RequestFacade@21a9c23e

servletPath:/filters
pathInfo:null
headers:
host: localhost:8080
user-agent: curl/8.0.1
accept: */*
x-user: A


Security filter chain: [
  DisableEncodeUrlFilter
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  CsrfFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  AuthorizationFilter
]


************************************************************


2023-05-25 22:10:48.438 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@7f18dabf, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@593ea2b2, org.springframework.security.web.context.SecurityContextPersistenceFilter@78115e1b, org.springframework.security.web.header.HeaderWriterFilter@6cfa908e, org.springframework.security.web.csrf.CsrfFilter@59929929, org.springframework.security.web.authentication.logout.LogoutFilter@58be5f1e, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@3d9ed909, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@62d540a8, org.springframework.security.web.session.SessionManagementFilter@7db987f9, org.springframework.security.web.access.ExceptionTranslationFilter@75c8948d, org.springframework.security.web.access.intercept.AuthorizationFilter@43fcbf99]] (1/1)
2023-05-25 22:10:48.442 DEBUG 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Securing GET /filters
2023-05-25 22:10:48.448 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking DisableEncodeUrlFilter (1/11)
2023-05-25 22:10:48.456 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking WebAsyncManagerIntegrationFilter (2/11)
2023-05-25 22:10:48.460 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking SecurityContextPersistenceFilter (3/11)
2023-05-25 22:10:48.464 TRACE 29080 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2023-05-25 22:10:48.467 TRACE 29080 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : Created SecurityContextImpl [Null authentication]
2023-05-25 22:10:48.467 DEBUG 29080 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2023-05-25 22:10:48.468 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking HeaderWriterFilter (4/11)
2023-05-25 22:10:48.469 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking CsrfFilter (5/11)
2023-05-25 22:10:48.470 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.csrf.CsrfFilter         : Did not protect against CSRF since request did not match CsrfNotRequired [TRACE, HEAD, GET, OPTIONS]
2023-05-25 22:10:48.472 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking LogoutFilter (6/11)
2023-05-25 22:10:48.473 TRACE 29080 --- [nio-8080-exec-1] o.s.s.w.a.logout.LogoutFilter            : Did not match request to Ant [pattern='/logout', POST]       
2023-05-25 22:10:48.475 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking RequestCacheAwareFilter (7/11)
2023-05-25 22:10:48.478 TRACE 29080 --- [nio-8080-exec-1] o.s.s.w.s.HttpSessionRequestCache        : No saved request
2023-05-25 22:10:48.479 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking SecurityContextHolderAwareRequestFilter (8/11)      
2023-05-25 22:10:48.480 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking SessionManagementFilter (9/11)
2023-05-25 22:10:48.482 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking ExceptionTranslationFilter (10/11)
2023-05-25 22:10:48.483 TRACE 29080 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking AuthorizationFilter (11/11)
2023-05-25 22:10:48.484 TRACE 29080 --- [nio-8080-exec-1] estMatcherDelegatingAuthorizationManager : Authorizing SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@3e406d3a]
2023-05-25 22:10:48.485 TRACE 29080 --- [nio-8080-exec-1] estMatcherDelegatingAuthorizationManager : Checking authorization on SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@3e406d3a] using org.springframework.security.authorization.AuthenticatedAuthorizationManager@13bd82ef
2023-05-25 22:10:48.488 TRACE 29080 --- [nio-8080-exec-1] o.s.s.w.a.ExceptionTranslationFilter     : Sending to authentication entry point since authentication failed

org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
        at org.springframework.security.web.access.intercept.AuthorizationFilter.getAuthentication(AuthorizationFilter.java:143) ~[spring-security-web-5.8.3.jar:5.8.3]
        at org.springframework.security.authorization.AuthenticatedAuthorizationManager.check(AuthenticatedAuthorizationManager.java:115) ~[spring-security-core-5.8.3.jar:5.8.3]
    // omitted
```

Let's zoom in on this particular message - `An Authentication object was not found in the SecurityContext`. This means there is no chance for `Authentication` to happen and `SecurityContext` was not constructed, since no Filter is handling it.

In short, you need to ensure that the `Authentication` filter is registered as part of the `SecurityFilterChain`. If that is the case, what can we do to ensure that?

# Solution

## Do not register as `@Bean`

Simply remove `@Bean` annotation on `RequestHeaderAuthenticationFilter` and register it as part of `SecurityFilterChain` manually

```java
// removed @Bean
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter(AuthenticationManager authenticationManager) {
    RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter = new RequestHeaderAuthenticationFilter();
    requestHeaderAuthenticationFilter.setPrincipalRequestHeader("X-User");
    requestHeaderAuthenticationFilter.setExceptionIfHeaderMissing(true);
    requestHeaderAuthenticationFilter.setAuthenticationManager(authenticationManager);

    return requestHeaderAuthenticationFilter;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
    return http
        .anonymous(AbstractHttpConfigurer::disable)
        .authorizeHttpRequests(authz -> authz.anyRequest().authenticated())
        // register the filter manually
        .addFilter(requestHeaderAuthenticationFilter(authenticationManager))
        .build();
}
```

Now, in the `SecurityFilterChain`, we can see the following

```powershell
Security filter chain: [
  DisableEncodeUrlFilter
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  CsrfFilter
  LogoutFilter
  RequestHeaderAuthenticationFilter << look at this
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  AuthorizationFilter
]
```

Notice that `RequestHeaderAuthenticationFilter` is now part of the `SecurityFilterChain` and no longer exist as part of the servlet `Filter`?

```powershell
2023-05-25 23:45:05.014 DEBUG 26544 --- [  restartedMain] o.s.b.w.s.ServletContextInitializerBeans : Mapping filters: springSecurityFilterChain urls=[/*] order=-100, filterRegistrationBean urls=[/*] order=2147483647, filterRegistrationBean urls=[/*] order=2147483647, characterEncodingFilter urls=[/*] order=-2147483648, formContentFilter urls=[/*] order=-9900, requestContextFilter urls=[/*] order=-105
```

Now, if you make an HTTP request to the server, you will encounter the following error

```bash
curl localhost:8080
```

```java
2023-05-23 23:45:53.779 ERROR 14644 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException: X-User header not found in request.
        at org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter.getPreAuthenticatedPrincipal(RequestHeaderAuthenticationFilter.java:64) ~[spring-security-web-5.8.3.jar:5.8.3]
        at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doAuthenticate(AbstractPreAuthenticatedProcessingFilter.java:189) ~[spring-security-web-5.8.3.jar:5.8.3]
    // omitted
```

We can see that `RequestHeaderAuthenticationFilter` is being triggered, and that it requires `X-User` header now, as per what we have configured.

## Configure FilterRegistrationBean

What if I must register `RequestHeaderAuthenticationFilter` as a `@Bean` and I want to exclude it from registering with the `Servlet Filter`?

You can declare a `FilterRegistrationBean` and set it to `false`

```java
@Bean
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter(AuthenticationManager authenticationManager) {
    RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter = new RequestHeaderAuthenticationFilter();
    requestHeaderAuthenticationFilter.setPrincipalRequestHeader("X-User");
    requestHeaderAuthenticationFilter.setExceptionIfHeaderMissing(true);
    requestHeaderAuthenticationFilter.setAuthenticationManager(authenticationManager);

    return requestHeaderAuthenticationFilter;
}

@Bean
public FilterRegistrationBean<RequestHeaderAuthenticationFilter> registration(RequestHeaderAuthenticationFilter filter) {
    FilterRegistrationBean<RequestHeaderAuthenticationFilter> registration = new FilterRegistrationBean<>(filter);
    registration.setEnabled(false);
    return registration;
}
```

When the application start-up, it will show that `RequestHeaderAuthenticationFilter` is not being registered. Similar to what we have, when we don't register `RequestHeaderAuthenticationFilter` as a `@Bean`.

```powershell
2023-05-25 23:45:05.014 DEBUG 26544 --- [  restartedMain] o.s.b.w.s.ServletContextInitializerBeans : Mapping filters: springSecurityFilterChain urls=[/*] order=-100, filterRegistrationBean urls=[/*] order=2147483647, filterRegistrationBean urls=[/*] order=2147483647, characterEncodingFilter urls=[/*] order=-2147483648, formContentFilter urls=[/*] order=-9900, requestContextFilter urls=[/*] order=-105
```

# Conclusion

We looked at why a Filter - `RequestHeaderAuthenticationFilter` - is not automatically registered as part of `SecurityFilterChain`. And moved on to see how we can register it manually, and how to disable the automatic registration of Filter in `Servlet` via `FilterRegistrationBean`.

Knowing that `Spring Boot` automatically registers any `Servlet`, `Filter`, or servlet `*Listener` instance that is a Spring bean with the embedded container is important because sometimes you may encounter an issue where your Filter gets invoked twice.

# **Source Code**

As usual, the full source code is available on [**GitHub**](https://github.com/bwgjoseph/tutorials/tree/main/spring-security-filter-chain)**.**

# References

* [https://stackoverflow.com/questions/39314176/filter-invoke-twice-when-register-as-spring-bean](https://stackoverflow.com/questions/39314176/filter-invoke-twice-when-register-as-spring-bean)
    
* [https://stackoverflow.com/questions/28421966/prevent-spring-boot-from-registering-a-servlet-filter](https://stackoverflow.com/questions/28421966/prevent-spring-boot-from-registering-a-servlet-filter)
    
* [https://github.com/spring-projects/spring-boot/issues/31142](https://github.com/spring-projects/spring-boot/issues/31142)
    
* [https://github.com/spring-projects/spring-boot/issues/31511](https://github.com/spring-projects/spring-boot/issues/31511)
