[[webflux-cors]]
= CORS
[.small]#<<web.adoc#mvc-cors,Same in Spring MVC>>#




[[webflux-cors-intro]]
== Introduction
[.small]#<<web.adoc#mvc-cors-intro,Same in Spring MVC>>#

For security reasons browsers prohibit AJAX calls to resources outside the current origin.
For example you could have your bank account in one tab and evil.com in another. Scripts
from evil.com should not be able to make AJAX requests to your bank API with your
credentials, e.g. withdrawing money from your account!

Cross-Origin Resource Sharing (CORS) is a http://www.w3.org/TR/cors/[W3C specification]
implemented by http://caniuse.com/#feat=cors[most browsers] that allows you to specify
what kind of cross domain requests are authorized rather than using less secure and less
powerful workarounds based on IFRAME or JSONP.




[[webflux-cors-processing]]
== Processing
[.small]#<<web.adoc#mvc-cors-processing,Same in Spring MVC>>#

The CORS specification distinguishes between preflight, simple, and actual requests.
To learn how CORS works, you can read
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS[this article], among
many others, or refer to the specification for more details.

Spring WebFlux ``HandlerMapping``'s provide built-in support for CORS. After successfully
mapping a request to a handler, ``HandlerMapping``'s check the CORS configuration for the
given request and handler and take further actions. Preflight requests are handled
directly while simple and actual CORS requests are intercepted, validated, and have
required CORS response headers set.

In order to enable cross-origin requests (i.e. the `Origin` header is present and
differs from the host of the request) you need to have some explicitly declared CORS
configuration. If no matching CORS configuration is found, preflight requests are
rejected. No CORS headers are added to the responses of simple and actual CORS requests
and consequently browsers reject them.

Each `HandlerMapping` can be
{api-spring-framework}/web/reactive/handler/AbstractHandlerMapping.html#setCorsConfigurations-java.util.Map-[configured]
individually with URL pattern based `CorsConfiguration` mappings. In most cases applications
will use the WebFlux Java config to declare such mappings, which results in a single,
global map passed to all ``HadlerMappping``'s.

Global CORS configuration at the `HandlerMapping` level can be combined with more
fine-grained, handler-level CORS configuration. For example annotated controllers can use
class or method-level `@CrossOrigin` annotations (other handlers can implement
`CorsConfigurationSource`).

The rules for combining global and local configuration are generally additive -- e.g.
all global and all local origins. For those attributes where only a single value can be
accepted such as `allowCredentials` and `maxAge`, the local overrides the global value. See
{api-spring-framework}/web/cors/CorsConfiguration.html#combine-org.springframework.web.cors.CorsConfiguration-[`CorsConfiguration#combine(CorsConfiguration)`]
for more details.

[TIP]
====
To learn more from the source or make advanced customizations, check:

* `CorsConfiguration`
* `CorsProcessor`, `DefaultCorsProcessor`
* `AbstractHandlerMapping`
====




[[webflux-cors-controller]]
== @CrossOrigin
[.small]#<<web.adoc#mvc-cors-controller,Same in Spring MVC>>#

The {api-spring-framework}/web/bind/annotation/CrossOrigin.html[`@CrossOrigin`]
annotation enables cross-origin requests on annotated controller methods:

[source,java,indent=0]
[subs="verbatim,quotes"]
----
@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin
	@GetMapping("/{id}")
	public Mono<Account> retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public Mono<Void> remove(@PathVariable Long id) {
		// ...
	}
}
----

By default `@CrossOrigin` allows:

* All origins.
* All headers.
* All HTTP methods to which the controller method is mapped.
* `allowedCredentials` is not enabled by default since that establishes a trust level
that exposes sensitive user-specific information such as cookies and CSRF tokens, and
should only be used where appropriate.
* `maxAge` is set to 30 minutes.

`@CrossOrigin` is supported at the class level too and inherited by all methods:

[source,java,indent=0]
[subs="verbatim,quotes"]
----
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@GetMapping("/{id}")
	public Mono<Account> retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public Mono<Void> remove(@PathVariable Long id) {
		// ...
	}
}
----

`CrossOrigin` can be used at both class and method-level:

[source,java,indent=0]
[subs="verbatim,quotes"]
----
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin("http://domain2.com")
	@GetMapping("/{id}")
	public Mono<Account> retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public Mono<Void> remove(@PathVariable Long id) {
		// ...
	}
}
----




[[webflux-cors-global]]
== Global Config
[.small]#<<web.adoc#mvc-cors-global,Same in Spring MVC>>#

In addition to fine-grained, controller method level configuration you'll probably want to
define some global CORS configuration too. You can set URL-based `CorsConfiguration`
mappings individually on any `HandlerMapping`. Most applications however will use the
WebFlux Java config to do that.

By default global configuration enables the following:

* All origins.
* All headers.
* `GET`, `HEAD`, and `POST` methods.
* `allowedCredentials` is not enabled by default since that establishes a trust level
that exposes sensitive user-specific information such as cookies and CSRF tokens, and
should only be used where appropriate.
* `maxAge` is set to 30 minutes.

To enable CORS in the WebFlux Java config, use the `CorsRegistry` callback:

[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

	@Override
	public void addCorsMappings(CorsRegistry registry) {

		registry.addMapping("/api/**")
			.allowedOrigins("http://domain2.com")
			.allowedMethods("PUT", "DELETE")
			.allowedHeaders("header1", "header2", "header3")
			.exposedHeaders("header1", "header2")
			.allowCredentials(true).maxAge(3600);

		// Add more mappings...
	}
}
----


[[webflux-cors-webfilter]]
== CORS WebFilter
[.small]#<<web.adoc#mvc-cors-filter,Same in Spring MVC>>#

You can apply CORS support through the built-in
{api-spring-framework}/web/cors/reactive/CorsWebFilter.html[`CorsWebFilter`], which is a
good fit with <<webflux-fn,functional endpoints>>.

To configure the filter, you can declare a `CorsWebFilter` bean and pass a
`CorsConfigurationSource` to its constructor:

[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Bean
CorsWebFilter corsFilter() {

	CorsConfiguration config = new CorsConfiguration();

	// Possibly...
	// config.applyPermitDefaultValues()

	config.setAllowCredentials(true);
	config.addAllowedOrigin("http://domain1.com");
	config.addAllowedHeader("*");
	config.addAllowedMethod("*");

	UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
	source.registerCorsConfiguration("/**", config);

	return new CorsWebFilter(source);
}
----

