|  | @@ -167,44 +167,222 @@ In fact, a `SecurityFilterChain` might have zero security `Filter` instances if
 | 
	
		
			
				|  |  |  == Security Filters
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  The Security Filters are inserted into the <<servlet-filterchainproxy>> with the <<servlet-securityfilterchain>> API.
 | 
	
		
			
				|  |  | -The <<servlet-filters-review,order of `Filter`>> instances matters.
 | 
	
		
			
				|  |  | -It is typically not necessary to know the ordering of Spring Security's `Filter` instances.
 | 
	
		
			
				|  |  | -However, there are times that it is beneficial to know the ordering.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The following is a comprehensive list of Spring Security Filter ordering:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -* xref:servlet/authentication/session-management.adoc#session-mgmt-force-session-creation[`ForceEagerSessionCreationFilter`]
 | 
	
		
			
				|  |  | -* `ChannelProcessingFilter`
 | 
	
		
			
				|  |  | -* `WebAsyncManagerIntegrationFilter`
 | 
	
		
			
				|  |  | -* `SecurityContextPersistenceFilter`
 | 
	
		
			
				|  |  | -* `HeaderWriterFilter`
 | 
	
		
			
				|  |  | -* `CorsFilter`
 | 
	
		
			
				|  |  | -* `CsrfFilter`
 | 
	
		
			
				|  |  | -* `LogoutFilter`
 | 
	
		
			
				|  |  | -* `OAuth2AuthorizationRequestRedirectFilter`
 | 
	
		
			
				|  |  | -* `Saml2WebSsoAuthenticationRequestFilter`
 | 
	
		
			
				|  |  | -* `X509AuthenticationFilter`
 | 
	
		
			
				|  |  | -* `AbstractPreAuthenticatedProcessingFilter`
 | 
	
		
			
				|  |  | -* `CasAuthenticationFilter`
 | 
	
		
			
				|  |  | -* `OAuth2LoginAuthenticationFilter`
 | 
	
		
			
				|  |  | -* `Saml2WebSsoAuthenticationFilter`
 | 
	
		
			
				|  |  | -* xref:servlet/authentication/passwords/form.adoc#servlet-authentication-usernamepasswordauthenticationfilter[`UsernamePasswordAuthenticationFilter`]
 | 
	
		
			
				|  |  | -* `DefaultLoginPageGeneratingFilter`
 | 
	
		
			
				|  |  | -* `DefaultLogoutPageGeneratingFilter`
 | 
	
		
			
				|  |  | -* `ConcurrentSessionFilter`
 | 
	
		
			
				|  |  | -* xref:servlet/authentication/passwords/digest.adoc#servlet-authentication-digest[`DigestAuthenticationFilter`]
 | 
	
		
			
				|  |  | -* `BearerTokenAuthenticationFilter`
 | 
	
		
			
				|  |  | -* xref:servlet/authentication/passwords/basic.adoc#servlet-authentication-basic[`BasicAuthenticationFilter`]
 | 
	
		
			
				|  |  | -* <<requestcacheawarefilter,RequestCacheAwareFilter>>
 | 
	
		
			
				|  |  | -* `SecurityContextHolderAwareRequestFilter`
 | 
	
		
			
				|  |  | -* `JaasApiIntegrationFilter`
 | 
	
		
			
				|  |  | -* `RememberMeAuthenticationFilter`
 | 
	
		
			
				|  |  | -* `AnonymousAuthenticationFilter`
 | 
	
		
			
				|  |  | -* `OAuth2AuthorizationCodeGrantFilter`
 | 
	
		
			
				|  |  | -* `SessionManagementFilter`
 | 
	
		
			
				|  |  | -* <<servlet-exceptiontranslationfilter,`ExceptionTranslationFilter`>>
 | 
	
		
			
				|  |  | -* xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`]
 | 
	
		
			
				|  |  | -* `SwitchUserFilter`
 | 
	
		
			
				|  |  | +Those filters can be used for a number of different purposes, like xref:servlet/authentication/index.adoc[authentication], xref:servlet/authorization/index.adoc[authorization], xref:servlet/exploits/index.adoc[exploit protection], and more.
 | 
	
		
			
				|  |  | +The filters are executed in a specific order to guarantee that they are invoked at the right time, for example, the `Filter` that performs authentication should be invoked before the `Filter` that performs authorization.
 | 
	
		
			
				|  |  | +It is typically not necessary to know the ordering of Spring Security's ``Filter``s.
 | 
	
		
			
				|  |  | +However, there are times that it is beneficial to know the ordering, if you want to know them, you can check the {gh-url}/config/src/main/java/org/springframework/security/config/annotation/web/builders/FilterOrderRegistration.java[`FilterOrderRegistration` code].
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +To exemplify the above paragraph, let's consider the following security configuration:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +====
 | 
	
		
			
				|  |  | +.Java
 | 
	
		
			
				|  |  | +[source,java,role="primary"]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +@Configuration
 | 
	
		
			
				|  |  | +@EnableWebSecurity
 | 
	
		
			
				|  |  | +public class SecurityConfig {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @Bean
 | 
	
		
			
				|  |  | +    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
 | 
	
		
			
				|  |  | +        http
 | 
	
		
			
				|  |  | +            .csrf(Customizer.withDefaults())
 | 
	
		
			
				|  |  | +            .authorizeHttpRequests(authorize -> authorize
 | 
	
		
			
				|  |  | +                .anyRequest().authenticated()
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +            .httpBasic(Customizer.withDefaults())
 | 
	
		
			
				|  |  | +            .formLogin(Customizer.withDefaults());
 | 
	
		
			
				|  |  | +        return http.build();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +.Kotlin
 | 
	
		
			
				|  |  | +[source,kotlin,role="secondary"]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +import org.springframework.security.config.web.servlet.invoke
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +@Configuration
 | 
	
		
			
				|  |  | +@EnableWebSecurity
 | 
	
		
			
				|  |  | +class SecurityConfig {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @Bean
 | 
	
		
			
				|  |  | +    fun filterChain(http: HttpSecurity): SecurityFilterChain {
 | 
	
		
			
				|  |  | +        http {
 | 
	
		
			
				|  |  | +            csrf { }
 | 
	
		
			
				|  |  | +            authorizeHttpRequests {
 | 
	
		
			
				|  |  | +                authorize(anyRequest, authenticated)
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            httpBasic { }
 | 
	
		
			
				|  |  | +            formLogin { }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return http.build()
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +====
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The above configuration will result in the following `Filter` ordering:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[cols="1,1", options="header"]
 | 
	
		
			
				|  |  | +|====
 | 
	
		
			
				|  |  | +| Filter | Added by
 | 
	
		
			
				|  |  | +| xref:servlet/exploits/csrf.adoc[CsrfFilter] | `HttpSecurity#csrf`
 | 
	
		
			
				|  |  | +| xref:servlet/authentication/passwords/form.adoc#servlet-authentication-form[UsernamePasswordAuthenticationFilter] | `HttpSecurity#formLogin`
 | 
	
		
			
				|  |  | +| xref:servlet/authentication/passwords/basic.adoc[BasicAuthenticationFilter] | `HttpSecurity#httpBasic`
 | 
	
		
			
				|  |  | +| xref:servlet/authorization/authorize-http-requests.adoc[AuthorizationFilter] | `HttpSecurity#authorizeHttpRequests`
 | 
	
		
			
				|  |  | +|====
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +1. First, the `CsrfFilter` is invoked to protect against xref:servlet/exploits/csrf.adoc[CSRF attacks].
 | 
	
		
			
				|  |  | +2. Second, the authentication filters are invoked to authenticate the request.
 | 
	
		
			
				|  |  | +3. Third, the `AuthorizationFilter` is invoked to authorize the request.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[NOTE]
 | 
	
		
			
				|  |  | +====
 | 
	
		
			
				|  |  | +There might be other `Filter` instances that are not listed above.
 | 
	
		
			
				|  |  | +If you want to see the list of filters invoked for a particular request, you can <<servlet-print-filters,print them>>.
 | 
	
		
			
				|  |  | +====
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[[servlet-print-filters]]
 | 
	
		
			
				|  |  | +=== Printing the Security Filters
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Often times, it is useful to see the list of security ``Filter``s that are invoked for a particular request.
 | 
	
		
			
				|  |  | +For example, you want to make sure that the <<adding-custom-filter,filter you have added>> is in the list of the security filters.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The list of filters is printed at INFO level on the application startup, so you can see something like the following on the console output for example:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[source,text,role="terminal"]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +2023-06-14T08:55:22.321-03:00  INFO 76975 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Will secure any request with [
 | 
	
		
			
				|  |  | +org.springframework.security.web.session.DisableEncodeUrlFilter@404db674,
 | 
	
		
			
				|  |  | +org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@50f097b5,
 | 
	
		
			
				|  |  | +org.springframework.security.web.context.SecurityContextHolderFilter@6fc6deb7,
 | 
	
		
			
				|  |  | +org.springframework.security.web.header.HeaderWriterFilter@6f76c2cc,
 | 
	
		
			
				|  |  | +org.springframework.security.web.csrf.CsrfFilter@c29fe36,
 | 
	
		
			
				|  |  | +org.springframework.security.web.authentication.logout.LogoutFilter@ef60710,
 | 
	
		
			
				|  |  | +org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@7c2dfa2,
 | 
	
		
			
				|  |  | +org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@4397a639,
 | 
	
		
			
				|  |  | +org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7add838c,
 | 
	
		
			
				|  |  | +org.springframework.security.web.authentication.www.BasicAuthenticationFilter@5cc9d3d0,
 | 
	
		
			
				|  |  | +org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7da39774,
 | 
	
		
			
				|  |  | +org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@32b0876c,
 | 
	
		
			
				|  |  | +org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3662bdff,
 | 
	
		
			
				|  |  | +org.springframework.security.web.access.ExceptionTranslationFilter@77681ce4,
 | 
	
		
			
				|  |  | +org.springframework.security.web.access.intercept.AuthorizationFilter@169268a7]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +And that will give a pretty good idea of the security filters that are configured for <<servlet-securityfilterchain,each filter chain>>.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +But that is not all, you can also configure your application to print the invocation of each individual filter for each request.
 | 
	
		
			
				|  |  | +That is helpful to see if the filter you have added is invoked for a particular request or to check where an exception is coming from.
 | 
	
		
			
				|  |  | +To do that, you can configure your application to <<servlet-logging,log the security events>>.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[[adding-custom-filter]]
 | 
	
		
			
				|  |  | +=== Adding a Custom Filter to the Filter Chain
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Mostly of the times, the default security filters are enough to provide security to your application.
 | 
	
		
			
				|  |  | +However, there might be times that you want to add a custom `Filter` to the security filter chain.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +For example, let's say that you want to add a `Filter` that gets a tenant id header and check if the current user has access to that tenant.
 | 
	
		
			
				|  |  | +The previous description already gives us a clue on where to add the filter, since we need to know the current user, we need to add it after the authentication filters.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +First, let's create the `Filter`:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[source,java]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +import java.io.IOException;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import jakarta.servlet.Filter;
 | 
	
		
			
				|  |  | +import jakarta.servlet.FilterChain;
 | 
	
		
			
				|  |  | +import jakarta.servlet.ServletException;
 | 
	
		
			
				|  |  | +import jakarta.servlet.ServletRequest;
 | 
	
		
			
				|  |  | +import jakarta.servlet.ServletResponse;
 | 
	
		
			
				|  |  | +import jakarta.servlet.http.HttpServletRequest;
 | 
	
		
			
				|  |  | +import jakarta.servlet.http.HttpServletResponse;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import org.springframework.security.access.AccessDeniedException;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +public class TenantFilter implements Filter {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @Override
 | 
	
		
			
				|  |  | +    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 | 
	
		
			
				|  |  | +        HttpServletRequest request = (HttpServletRequest) servletRequest;
 | 
	
		
			
				|  |  | +        HttpServletResponse response = (HttpServletResponse) servletResponse;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        String tenantId = request.getHeader("X-Tenant-Id"); <1>
 | 
	
		
			
				|  |  | +        boolean hasAccess = isUserAllowed(tenantId); <2>
 | 
	
		
			
				|  |  | +        if (hasAccess) {
 | 
	
		
			
				|  |  | +            filterChain.doFilter(request, response); <3>
 | 
	
		
			
				|  |  | +            return;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        throw new AccessDeniedException("Access denied"); <4>
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The sample code above does the following:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<1> Get the tenant id from the request header.
 | 
	
		
			
				|  |  | +<2> Check if the current user has access to the tenant id.
 | 
	
		
			
				|  |  | +<3> If the user has access, then invoke the rest of the filters in the chain.
 | 
	
		
			
				|  |  | +<4> If the user does not have access, then throw an `AccessDeniedException`.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[TIP]
 | 
	
		
			
				|  |  | +====
 | 
	
		
			
				|  |  | +Instead of implementing `Filter`, you can extend from {spring-framework-api-url}org/springframework/web/filter/OncePerRequestFilter.html[OncePerRequestFilter] which is a base class for filters that are only invoked once per request and provides a `doFilterInternal` method with the `HttpServletRequest` and `HttpServletResponse` parameters.
 | 
	
		
			
				|  |  | +====
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Now, we need to add the filter to the security filter chain.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +====
 | 
	
		
			
				|  |  | +.Java
 | 
	
		
			
				|  |  | +[source,java,role="primary"]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +@Bean
 | 
	
		
			
				|  |  | +SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
 | 
	
		
			
				|  |  | +    http
 | 
	
		
			
				|  |  | +        // ...
 | 
	
		
			
				|  |  | +        .addFilterBefore(new TenantFilter(), AuthorizationFilter.class); <1>
 | 
	
		
			
				|  |  | +    return http.build();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +.Kotlin
 | 
	
		
			
				|  |  | +[source,kotlin,role="secondary"]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +@Bean
 | 
	
		
			
				|  |  | +fun filterChain(http: HttpSecurity): SecurityFilterChain {
 | 
	
		
			
				|  |  | +    http
 | 
	
		
			
				|  |  | +        // ...
 | 
	
		
			
				|  |  | +        .addFilterBefore(TenantFilter(), AuthorizationFilter::class.java) <1>
 | 
	
		
			
				|  |  | +    return http.build()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +====
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<1> Use `HttpSecurity#addFilterBefore` to add the `TenantFilter` before the `AuthorizationFilter`.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +By adding the filter before the `AuthorizationFilter` we are making sure that the `TenantFilter` is invoked after the authentication filters.
 | 
	
		
			
				|  |  | +You can also use `HttpSecurity#addFilterAfter` to add the filter after a particular filter or `HttpSecurity#addFilterAt` to add the filter at a particular filter position in the filter chain.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +And that's it, now the `TenantFilter` will be invoked in the filter chain and will check if the current user has access to the tenant id.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Be careful when you declare your filter as a Spring bean, either by annotating it with `@Component` or by declaring it as a bean in your configuration, because Spring Boot will automatically {spring-boot-reference-url}web.html#web.servlet.embedded-container.servlets-filters-listeners.beans[register it with the embedded container].
 | 
	
		
			
				|  |  | +That may cause the filter to be invoked twice, once by the container and once by Spring Security and in a different order.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +If you still want to declare your filter as a Spring bean to take advantage of dependency injection for example, and avoid the duplicate invocation, you can tell Spring Boot to not register it with the container by declaring a `FilterRegistrationBean` bean and setting its `enabled` property to `false`:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[source,java]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +@Bean
 | 
	
		
			
				|  |  | +public FilterRegistrationBean<TenantFilter> tenantFilterRegistration(TenantFilter filter) {
 | 
	
		
			
				|  |  | +    FilterRegistrationBean<TenantFilter> registration = new FilterRegistrationBean<>(filter);
 | 
	
		
			
				|  |  | +    registration.setEnabled(false);
 | 
	
		
			
				|  |  | +    return registration;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  [[servlet-exceptiontranslationfilter]]
 | 
	
		
			
				|  |  |  == Handling Security Exceptions
 | 
	
	
		
			
				|  | @@ -336,3 +514,52 @@ XML::
 | 
	
		
			
				|  |  |  === RequestCacheAwareFilter
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  The {security-api-url}org/springframework/security/web/savedrequest/RequestCacheAwareFilter.html[`RequestCacheAwareFilter`] uses the <<requestcache,`RequestCache`>> to save the `HttpServletRequest`.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[[servlet-logging]]
 | 
	
		
			
				|  |  | +== Logging
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Spring Security provides comprehensive logging of all security related events at the DEBUG and TRACE level.
 | 
	
		
			
				|  |  | +This can be very useful when debugging your application because for security measures Spring Security does not add any detail of why a request has been rejected to the response body.
 | 
	
		
			
				|  |  | +If you come across a 401 or 403 error, it is very likely that you will find a log message that will help you understand what is going on.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Let's consider an example where a user tries to make a `POST` request to a resource that has xref:servlet/exploits/csrf.adoc[CSRF protection] enabled without the CSRF token.
 | 
	
		
			
				|  |  | +With no logs, the user will see a 403 error with no explanation of why the request was rejected.
 | 
	
		
			
				|  |  | +However, if you enable logging for Spring Security, you will see a log message like this:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[source,text]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +2023-06-14T09:44:25.797-03:00 DEBUG 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Securing POST /hello
 | 
	
		
			
				|  |  | +2023-06-14T09:44:25.797-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking DisableEncodeUrlFilter (1/15)
 | 
	
		
			
				|  |  | +2023-06-14T09:44:25.798-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking WebAsyncManagerIntegrationFilter (2/15)
 | 
	
		
			
				|  |  | +2023-06-14T09:44:25.800-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking SecurityContextHolderFilter (3/15)
 | 
	
		
			
				|  |  | +2023-06-14T09:44:25.801-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking HeaderWriterFilter (4/15)
 | 
	
		
			
				|  |  | +2023-06-14T09:44:25.802-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking CsrfFilter (5/15)
 | 
	
		
			
				|  |  | +2023-06-14T09:44:25.814-03:00 DEBUG 76975 --- [nio-8080-exec-1] o.s.security.web.csrf.CsrfFilter         : Invalid CSRF token found for http://localhost:8080/hello
 | 
	
		
			
				|  |  | +2023-06-14T09:44:25.814-03:00 DEBUG 76975 --- [nio-8080-exec-1] o.s.s.w.access.AccessDeniedHandlerImpl   : Responding with 403 status code
 | 
	
		
			
				|  |  | +2023-06-14T09:44:25.814-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match request to [Is Secure]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +It becomes clear that the CSRF token is missing and that is why the request is being denied.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +To configure your application to log all the security events, you can add the following to your application:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +====
 | 
	
		
			
				|  |  | +.application.properties in Spring Boot
 | 
	
		
			
				|  |  | +[source,properties,role="primary"]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +logging.level.org.springframework.security=TRACE
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +.logback.xml
 | 
	
		
			
				|  |  | +[source,xml,role="secondary"]
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +<configuration>
 | 
	
		
			
				|  |  | +    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
 | 
	
		
			
				|  |  | +        <!-- ... -->
 | 
	
		
			
				|  |  | +    </appender>
 | 
	
		
			
				|  |  | +    <!-- ... -->
 | 
	
		
			
				|  |  | +    <logger name="org.springframework.security" level="trace" additivity="false">
 | 
	
		
			
				|  |  | +        <appender-ref ref="Console" />
 | 
	
		
			
				|  |  | +    </logger>
 | 
	
		
			
				|  |  | +</configuration>
 | 
	
		
			
				|  |  | +----
 | 
	
		
			
				|  |  | +====
 |