[[servlet-headers]]
= Security HTTP Response Headers

You can use xref:features/exploits/headers.adoc#headers[Security HTTP Response Headers] to increase the security of web applications.
This section is dedicated to servlet-based support for Security HTTP Response Headers.

[[servlet-headers-default]]
== Default Security Headers

Spring Security provides a xref:features/exploits/headers.adoc#headers-default[default set of Security HTTP Response Headers] to provide secure defaults.
While each of these headers are considered best practice, it should be noted that not all clients use the headers, so additional testing is encouraged.

You can customize specific headers.
For example, assume that you want the defaults but you wish to specify `SAMEORIGIN` for <<servlet-headers-frame-options,X-Frame-Options>>.

You can do so with the following configuration:

.Customize Default Security Headers
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
		WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) {
		http
			// ...
			.headers(headers -> headers
				.frameOptions(frameOptions -> frameOptions
					.sameOrigin()
				)
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<frame-options policy="SAMEORIGIN" />
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                frameOptions {
                    sameOrigin = true
                }
            }
        }
    }
}
----
====

If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults.
The next code listing shows how to do so.

If you use Spring Security's configuration, the following adds only xref:features/exploits/headers.adoc#headers-cache-control[Cache Control]:

.Customize Cache Control Headers
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				// do not use any default headers unless explicitly listed
				.defaultsDisabled()
				.cacheControl(withDefaults())
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers defaults-disabled="true">
		<cache-control/>
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                // do not use any default headers unless explicitly listed
                defaultsDisabled = true
                cacheControl {
                }
            }
        }
    }
}
----
====

If necessary, you can disable all of the HTTP Security response headers with the following configuration:

.Disable All HTTP Security Headers
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers.disable());
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers disabled="true" />
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                disable()
            }
        }
    }
}
----
====

[[servlet-headers-cache-control]]
== Cache Control

Spring Security includes xref:features/exploits/headers.adoc#headers-cache-control[Cache Control] headers by default.

However, if you actually want to cache specific responses, your application can selectively invoke https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String)[`HttpServletResponse.setHeader(String,String)`] to override the header set by Spring Security.
You can use this to ensure that content (such as CSS, JavaScript, and images) is properly cached.

When you use Spring Web MVC, this is typically done within your configuration.
You can find details on how to do this in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources[Static Resources] portion of the Spring Reference documentation

If necessary, you can also disable Spring Security's cache control HTTP response headers.

.Cache Control Disabled
====
.Java
[source,java,role="primary"]
----
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) {
		http
			// ...
			.headers(headers -> headers
				.cacheControl(cache -> cache.disable())
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<cache-control disabled="true"/>
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
       http {
            headers {
                cacheControl {
                    disable()
                }
            }
        }
    }
}
----
====

[[servlet-headers-content-type-options]]
== Content Type Options

Spring Security includes xref:features/exploits/headers.adoc#headers-content-type-options[Content-Type] headers by default.
However, you can disable it:

.Content Type Options Disabled
====
.Java
[source,java,role="primary"]
----
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends
		WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) {
		http
			// ...
			.headers(headers -> headers
				.contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable())
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<content-type-options disabled="true"/>
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
       http {
            headers {
                contentTypeOptions {
                    disable()
                }
            }
        }
    }
}
----
====

[[servlet-headers-hsts]]
== HTTP Strict Transport Security (HSTS)

By default, Spring Security provides the xref:features/exploits/headers.adoc#headers-hsts[Strict Transport Security] header.
However, you can explicitly customize the results.
The following example explicitly provides HSTS:

.Strict Transport Security
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.httpStrictTransportSecurity(hsts -> hsts
					.includeSubDomains(true)
					.preload(true)
					.maxAgeInSeconds(31536000)
				)
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<hsts
			include-subdomains="true"
			max-age-seconds="31536000"
			preload="true" />
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            headers {
                httpStrictTransportSecurity {
                    includeSubDomains = true
                    preload = true
                    maxAgeInSeconds = 31536000
                }
            }
        }
    }
}
----
====

[[servlet-headers-hpkp]]
== HTTP Public Key Pinning (HPKP)
Spring Security provides servlet support for xref:features/exploits/headers.adoc#headers-hpkp[HTTP Public Key Pinning], but it is xref:features/exploits/headers.adoc#headers-hpkp-deprecated[no longer recommended].

You can enable HPKP headers with the following configuration:

.HTTP Public Key Pinning
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.httpPublicKeyPinning(hpkp -> hpkp
					.includeSubDomains(true)
					.reportUri("https://example.net/pkp-report")
					.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=")
				)
			);
	}
}
----
.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<hpkp
			include-subdomains="true"
			report-uri="https://example.net/pkp-report">
			<pins>
				<pin algorithm="sha256">d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=</pin>
				<pin algorithm="sha256">E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=</pin>
			</pins>
		</hpkp>
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            headers {
                httpPublicKeyPinning {
                    includeSubDomains = true
                    reportUri = "https://example.net/pkp-report"
                    pins = mapOf("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" to "sha256",
                            "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" to "sha256")
                }
            }
        }
    }
}
----
====

[[servlet-headers-frame-options]]
== X-Frame-Options

By default, Spring Security instructs browsers to block reflected XSS attacks by using the xref:features/exploits/headers.adoc#headers-frame-options[X-Frame-Options].

For example, the following configuration specifies that Spring Security should no longer instruct browsers to block the content:

.X-Frame-Options: SAMEORIGIN
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.frameOptions(frameOptions -> frameOptions
					.sameOrigin()
				)
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<frame-options
		policy="SAMEORIGIN" />
	</headers>
</http>
----


.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            headers {
                frameOptions {
                    sameOrigin = true
                }
            }
        }
    }
}
----
====

[[servlet-headers-xss-protection]]
== X-XSS-Protection

By default, Spring Security instructs browsers to block reflected XSS attacks by using the <<headers-xss-protection,X-XSS-Protection header>.
However, you can change this default.
For example, the following configuration specifies that Spring Security should no longer instruct browsers to block the content:

.X-XSS-Protection Customization
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.xssProtection(xss -> xss
					.block(false)
				)
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<xss-protection block="false"/>
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        // ...
        http {
            headers {
                xssProtection {
                    block = false
                }
            }
        }
    }
}
----
====

[[servlet-headers-csp]]
== Content Security Policy (CSP)

Spring Security does not add xref:features/exploits/headers.adoc#headers-csp[Content Security Policy] by default, because a reasonable default is impossible to know without knowing the context of the application.
The web application author must declare the security policy (or policies) to enforce or monitor for the protected resources.

Consider the following security policy:

.Content Security Policy Example
====
[source,http]
----
Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/
----
====

Given the preceding security policy, you can enable the CSP header:

.Content Security Policy
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) {
		http
			// ...
			.headers(headers -> headers
				.contentSecurityPolicy(csp -> csp
					.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
				)
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<content-security-policy
			policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" />
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                contentSecurityPolicy {
                    policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
                }
            }
        }
    }
}
----
====

To enable the CSP `report-only` header, provide the following configuration:

.Content Security Policy Report Only
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
		WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.contentSecurityPolicy(csp -> csp
					.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
					.reportOnly()
				)
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<content-security-policy
			policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
			report-only="true" />
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                contentSecurityPolicy {
                    policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
                    reportOnly = true
                }
            }
        }
    }
}
----
====

[[servlet-headers-referrer]]
== Referrer Policy

Spring Security does not add xref:features/exploits/headers.adoc#headers-referrer[Referrer Policy] headers by default.
You can enable the Referrer Policy header by using the configuration:

.Referrer Policy
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) {
		http
			// ...
			.headers(headers -> headers
				.referrerPolicy(referrer -> referrer
					.policy(ReferrerPolicy.SAME_ORIGIN)
				)
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<referrer-policy policy="same-origin" />
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                referrerPolicy {
                    policy = ReferrerPolicy.SAME_ORIGIN
                }
            }
        }
    }
}
----
====

[[servlet-headers-feature]]
== Feature Policy

Spring Security does not add xref:features/exploits/headers.adoc#headers-feature[Feature Policy] headers by default.
Consider the following `Feature-Policy` header:

.Feature-Policy Example
====
[source]
----
Feature-Policy: geolocation 'self'
----
====

You can enable the preceding feature policy header by using the following configuration:

.Feature-Policy
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.featurePolicy("geolocation 'self'")
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<feature-policy policy-directives="geolocation 'self'" />
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                featurePolicy("geolocation 'self'")
            }
        }
    }
}
----
====

[[servlet-headers-permissions]]
== Permissions Policy

Spring Security does not add xref:features/exploits/headers.adoc#headers-permissions[Permissions Policy] headers by default.
Consider the following `Permissions-Policy` header:

.Permissions-Policy Example
====
[source]
----
Permissions-Policy: geolocation=(self)
----
====

You can enable the preceding permissions policy header using the following configuration:

.Permissions-Policy
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.permissionsPolicy(permissions -> permissions
					.policy("geolocation=(self)")
				)
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<permissions-policy policy="geolocation=(self)" />
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                permissionPolicy {
                    policy = "geolocation=(self)"
                }
            }
        }
    }
}
----
====

[[servlet-headers-clear-site-data]]
== Clear Site Data

Spring Security does not add xref:features/exploits/headers.adoc#headers-clear-site-data[Clear-Site-Data] headers by default.
Consider the following Clear-Site-Data header:

.Clear-Site-Data Example
====
----
Clear-Site-Data: "cache", "cookies"
----
====

You can send the preceding header on log out with the following configuration:

.Clear-Site-Data
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.logout((logout) -> logout
                .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES)))
			);
	}
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            // ...
            logout {
                addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(CACHE, COOKIES)))
            }
        }
    }
}
----
====

[[servlet-headers-custom]]
== Custom Headers
Spring Security has mechanisms to make it convenient to add the more common security headers to your application.
However, it also provides hooks to enable adding custom headers.

[[servlet-headers-static]]
=== Static Headers
There may be times when you wish to inject custom security headers that are not supported out of the box into your application.
Consider the following custom security header:

[source]
----
X-Custom-Security-Header: header-value
----

Given the preceding header, you could add the headers to the response by using the following configuration:

.StaticHeadersWriter
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"))
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<header name="X-Custom-Security-Header" value="header-value"/>
	</headers>
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                addHeaderWriter(StaticHeadersWriter("X-Custom-Security-Header","header-value"))
            }
        }
    }
}
----
====

[[servlet-headers-writer]]
=== Headers Writer
When the namespace or Java configuration does not support the headers you want, you can create a custom `HeadersWriter` instance or even provide a custom implementation of the `HeadersWriter`.

The next example use a custom instance of `XFrameOptionsHeaderWriter`.
If you wanted to explicitly configure <<servlet-headers-frame-options>>, you could do so with the following configuration:

.Headers Writer
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<header ref="frameOptionsWriter"/>
	</headers>
</http>
<!-- Requires the c-namespace.
See https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-c-namespace
-->
<beans:bean id="frameOptionsWriter"
	class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter"
	c:frameOptionsMode="SAMEORIGIN"/>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                addHeaderWriter(XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
            }
        }
    }
}
----
====

[[headers-delegatingrequestmatcherheaderwriter]]
=== DelegatingRequestMatcherHeaderWriter

At times, you may want to write a header only for certain requests.
For example, perhaps you want to protect only your login page from being framed.
You could use the `DelegatingRequestMatcherHeaderWriter` to do so.

The following configuration example uses `DelegatingRequestMatcherHeaderWriter`:

.DelegatingRequestMatcherHeaderWriter Java Configuration
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		RequestMatcher matcher = new AntPathRequestMatcher("/login");
		DelegatingRequestMatcherHeaderWriter headerWriter =
			new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
		http
			// ...
			.headers(headers -> headers
				.frameOptions(frameOptions -> frameOptions.disable())
				.addHeaderWriter(headerWriter)
			);
	}
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->

	<headers>
		<frame-options disabled="true"/>
		<header ref="headerWriter"/>
	</headers>
</http>

<beans:bean id="headerWriter"
	class="org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter">
	<beans:constructor-arg>
		<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"
			c:pattern="/login"/>
	</beans:constructor-arg>
	<beans:constructor-arg>
		<beans:bean
			class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter"/>
	</beans:constructor-arg>
</beans:bean>
----

.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        val matcher: RequestMatcher = AntPathRequestMatcher("/login")
        val headerWriter = DelegatingRequestMatcherHeaderWriter(matcher, XFrameOptionsHeaderWriter())
       http {
            headers {
                frameOptions {
                    disable()
                }
                addHeaderWriter(headerWriter)
            }
        }
    }
}
----
====
