or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

api-versioning.mdasync.mdconfiguration.mdcontent-negotiation.mdcontroller-annotations.mdcore-framework.mdcors.mddata-binding.mdexception-handling.mdflash-attributes.mdfunctional-endpoints.mdi18n.mdindex.mdinterceptors.mdmultipart.mdrequest-binding.mdresource-handling.mdresponse-handling.mduri-building.mdview-resolution.md
tile.json

cors.mddocs/

CORS Configuration

Cross-Origin Resource Sharing (CORS) support for enabling cross-origin requests with fine-grained control over allowed origins, methods, headers, and credentials.

Capabilities

@CrossOrigin

Enables Cross-Origin Resource Sharing on annotated controllers or handler methods.

/**
 * Marks the annotated handler method or class as supporting cross-origin requests.
 *
 * By default all origins and headers are allowed, credentials are not allowed, and
 * the maximum age is set to 1800 seconds (30 minutes). The list of HTTP methods is
 * set to the methods on the @RequestMapping if any, or to GET otherwise.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
    /**
     * Alias for {@link #origins}.
     */
    @AliasFor("origins")
    String[] value() default {};

    /**
     * List of allowed origins.
     * These values are placed in the Access-Control-Allow-Origin header of both the
     * pre-flight and actual responses.
     * "*" means all origins are allowed.
     * If undefined, all origins are allowed.
     */
    @AliasFor("value")
    String[] origins() default {};

    /**
     * Alternative to {@link #origins} that supports more flexible origin patterns.
     * In contrast to {@link #origins} which only supports "*" and concrete origins,
     * origin patterns are more flexible, e.g. "https://*.example.com" matches
     * "https://www.example.com" and "https://foo.example.com".
     */
    String[] originPatterns() default {};

    /**
     * List of request headers that can be used during the actual request.
     * This property controls the value of the pre-flight response's
     * Access-Control-Allow-Headers header.
     * "*" means all headers requested by the client are allowed.
     * If undefined, all requested headers are allowed.
     */
    String[] allowedHeaders() default {};

    /**
     * List of response headers that the user-agent will allow the client to access.
     * This property controls the value of actual response's Access-Control-Expose-Headers header.
     * If undefined, an empty exposed header list is used.
     */
    String[] exposedHeaders() default {};

    /**
     * List of supported HTTP request methods.
     * If undefined, methods are set to the methods on the @RequestMapping,
     * or to GET if not specified.
     */
    RequestMethod[] methods() default {};

    /**
     * Whether the browser should send credentials, such as cookies along with
     * cross domain requests, to the annotated endpoint.
     * The configured value is set on the Access-Control-Allow-Credentials response header.
     * NOTE: Be aware that this option establishes a high level of trust with the
     * configured domains and also increases the surface attack of the web application
     * by exposing sensitive user-specific information such as cookies and CSRF tokens.
     * If undefined, credentials are not allowed.
     */
    String allowCredentials() default "";

    /**
     * The maximum age (in seconds) of the cache duration for pre-flight responses.
     * This property controls the value of the Access-Control-Max-Age response header.
     * Setting this to a reasonable value can reduce the number of pre-flight request/response
     * interactions required by the browser.
     * A negative value means undefined.
     * If undefined, max age is set to 1800 seconds (30 minutes).
     */
    long maxAge() default -1;
}

Usage Example:

@RestController
@RequestMapping("/api/products")
@CrossOrigin(origins = "http://localhost:3000")
public class ProductController {

    @GetMapping
    public List<Product> getAllProducts() {
        return productService.findAll();
    }

    // Override CORS for specific method
    @PostMapping
    @CrossOrigin(
        origins = {"http://localhost:3000", "https://example.com"},
        methods = {RequestMethod.POST, RequestMethod.OPTIONS},
        allowedHeaders = {"Content-Type", "Authorization"},
        exposedHeaders = {"X-Total-Count"},
        allowCredentials = "true",
        maxAge = 3600
    )
    public Product createProduct(@RequestBody Product product) {
        return productService.save(product);
    }

    // Allow all origins for specific endpoint
    @GetMapping("/public/{id}")
    @CrossOrigin(origins = "*")
    public Product getPublicProduct(@PathVariable Long id) {
        return productService.findById(id);
    }
}

// CORS on class level
@RestController
@RequestMapping("/api/public")
@CrossOrigin(
    originPatterns = "https://*.example.com",
    methods = {RequestMethod.GET, RequestMethod.POST},
    maxAge = 3600
)
public class PublicApiController {

    @GetMapping("/data")
    public Data getData() {
        return dataService.getPublicData();
    }
}

CorsConfiguration

Configuration object for CORS that can be used programmatically.

/**
 * A container for CORS configuration along with methods to check against the
 * actual origin, HTTP methods, and headers of a given request.
 *
 * By default a newly created CorsConfiguration does not permit any cross-origin
 * requests and must be configured explicitly to indicate what should be allowed.
 */
public class CorsConfiguration {
    /**
     * Wildcard representing all origins, methods, or headers.
     */
    public static final String ALL = "*";

    /**
     * Create a new CorsConfiguration.
     */
    public CorsConfiguration() {}

    /**
     * Create a deep copy of the given CorsConfiguration.
     *
     * @param other the CorsConfiguration to copy
     */
    public CorsConfiguration(CorsConfiguration other) {}

    /**
     * Set the origins to allow, e.g. "http://domain1.com".
     * The special value "*" allows all domains.
     * By default this is not set.
     *
     * @param origins the origins to allow
     */
    public void setAllowedOrigins(List<String> origins) {}

    /**
     * Return the configured origins to allow, or null if none.
     *
     * @return the allowed origins
     */
    public List<String> getAllowedOrigins() {}

    /**
     * Add an origin to allow.
     *
     * @param origin the origin to add
     */
    public void addAllowedOrigin(String origin) {}

    /**
     * Alternative to setAllowedOrigins that supports more flexible patterns
     * for specifying the origins for which cross-origin requests are allowed.
     *
     * @param originPatterns the origin patterns to allow
     */
    public void setAllowedOriginPatterns(List<String> originPatterns) {}

    /**
     * Return the configured origin patterns to allow, or null if none.
     *
     * @return the allowed origin patterns
     */
    public List<String> getAllowedOriginPatterns() {}

    /**
     * Add an origin pattern to allow.
     *
     * @param originPattern the origin pattern to add
     */
    public void addAllowedOriginPattern(String originPattern) {}

    /**
     * Set the HTTP methods to allow, e.g. "GET", "POST", etc.
     * The special value "*" allows all methods.
     * If not set, only "GET" and "HEAD" are allowed.
     * By default this is not set.
     *
     * @param methods the HTTP methods to allow
     */
    public void setAllowedMethods(List<String> methods) {}

    /**
     * Return the allowed HTTP methods, or null in which case only "GET" and "HEAD" allowed.
     *
     * @return the allowed methods
     */
    public List<String> getAllowedMethods() {}

    /**
     * Add an HTTP method to allow.
     *
     * @param method the HTTP method to add
     */
    public void addAllowedMethod(HttpMethod method) {}

    /**
     * Add an HTTP method to allow.
     *
     * @param method the HTTP method to add
     */
    public void addAllowedMethod(String method) {}

    /**
     * Set the list of headers that a pre-flight request can list as allowed
     * for use during an actual request.
     * The special value "*" allows actual requests to send any header.
     * A header name is not required to be listed if it is one of:
     * Cache-Control, Content-Language, Expires, Last-Modified, or Pragma.
     * By default this is not set.
     *
     * @param headers the headers to allow
     */
    public void setAllowedHeaders(List<String> headers) {}

    /**
     * Return the allowed actual request headers, or null if none.
     *
     * @return the allowed headers
     */
    public List<String> getAllowedHeaders() {}

    /**
     * Add an actual request header to allow.
     *
     * @param header the header to add
     */
    public void addAllowedHeader(String header) {}

    /**
     * Set the list of response headers other than simple headers (i.e. Cache-Control,
     * Content-Language, Content-Type, Expires, Last-Modified, or Pragma) that an
     * actual response might have and can be exposed.
     * The special value "*" allows all headers to be exposed.
     * By default this is not set.
     *
     * @param headers the headers to expose
     */
    public void setExposedHeaders(List<String> headers) {}

    /**
     * Return the configured response headers to expose, or null if none.
     *
     * @return the exposed headers
     */
    public List<String> getExposedHeaders() {}

    /**
     * Add a response header to expose.
     * The special value "*" allows all headers to be exposed.
     *
     * @param header the header to expose
     */
    public void addExposedHeader(String header) {}

    /**
     * Whether user credentials are supported.
     * By default this is not set (i.e. user credentials are not supported).
     *
     * @param allowCredentials whether to allow credentials
     */
    public void setAllowCredentials(Boolean allowCredentials) {}

    /**
     * Return the configured allowCredentials flag, or null if none.
     *
     * @return whether credentials are allowed
     */
    public Boolean getAllowCredentials() {}

    /**
     * Configure how long, in seconds, the response from a pre-flight request
     * can be cached by clients.
     * By default this is not set.
     *
     * @param maxAge the max age in seconds
     */
    public void setMaxAge(Long maxAge) {}

    /**
     * Return the configured maxAge value, or null if none.
     *
     * @return the max age
     */
    public Long getMaxAge() {}

    /**
     * Check the origin of the request against the configured allowed origins.
     *
     * @param requestOrigin the origin to check
     * @return the origin to use for the response, or null which means the
     * request origin is not allowed
     */
    public String checkOrigin(String requestOrigin) {}

    /**
     * Check the HTTP method of the request against the configured allowed methods.
     *
     * @param requestMethod the HTTP method to check
     * @return the HTTP methods to list in the response of a pre-flight request,
     * or null if the supplied requestMethod is not allowed
     */
    public List<HttpMethod> checkHttpMethod(HttpMethod requestMethod) {}

    /**
     * Check the supplied request headers against the configured allowed headers.
     *
     * @param requestHeaders the request headers to check
     * @return the list of allowed headers to list in the response of a pre-flight
     * request, or null if none of the supplied request headers is allowed
     */
    public List<String> checkHeaders(List<String> requestHeaders) {}

    /**
     * Combine this configuration with another.
     *
     * @param other the other CorsConfiguration to combine with
     * @return the combined CorsConfiguration
     */
    public CorsConfiguration combine(CorsConfiguration other) {}
}

Usage Example:

@Configuration
public class CorsConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                    .allowedOrigins("http://localhost:3000", "https://example.com")
                    .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                    .allowedHeaders("*")
                    .exposedHeaders("Authorization", "X-Total-Count")
                    .allowCredentials(true)
                    .maxAge(3600);
            }
        };
    }

    // Programmatic CorsConfiguration
    @Bean
    public CorsConfiguration apiCorsConfiguration() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOriginPatterns(List.of("https://*.example.com"));
        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
        config.setAllowedHeaders(List.of("*"));
        config.setExposedHeaders(List.of("X-Total-Count", "X-Page-Number"));
        config.setAllowCredentials(true);
        config.setMaxAge(3600L);
        return config;
    }
}

CorsRegistry

Assists with the registration of CorsConfiguration mapped to a path pattern.

/**
 * Assists with the registration of global, URL pattern based CorsConfiguration mappings.
 */
public class CorsRegistry {
    /**
     * Enable cross-origin request handling for the specified path pattern.
     * Exact path mapping URIs (such as "/admin") are supported as well as
     * Ant-style path patterns (such as "/admin/**").
     *
     * @param pathPattern the path pattern to map to
     * @return a CorsRegistration for further configuration
     */
    public CorsRegistration addMapping(String pathPattern) {}

    /**
     * Return the registered CorsConfiguration objects.
     *
     * @return a Map with path patterns as keys and CorsConfiguration objects as values
     */
    protected Map<String, CorsConfiguration> getCorsConfigurations() {}
}

Usage Example:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // API endpoints
        registry.addMapping("/api/**")
            .allowedOrigins("http://localhost:3000")
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("Content-Type", "Authorization")
            .exposedHeaders("X-Total-Count")
            .allowCredentials(true)
            .maxAge(3600);

        // Public endpoints
        registry.addMapping("/public/**")
            .allowedOriginPatterns("*")
            .allowedMethods("GET")
            .maxAge(86400);

        // Admin endpoints - more restrictive
        registry.addMapping("/admin/**")
            .allowedOrigins("https://admin.example.com")
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("*")
            .allowCredentials(true)
            .maxAge(1800);
    }
}

Types

CorsRegistration

Assists with the creation of a CorsConfiguration instance for a given path pattern.

/**
 * Assists with the creation of a CorsConfiguration instance for a given URL path pattern.
 */
public class CorsRegistration {
    /**
     * Set the origins to allow. The special value "*" allows all domains.
     *
     * @param origins the origins to allow
     * @return this CorsRegistration for chaining
     */
    public CorsRegistration allowedOrigins(String... origins) {}

    /**
     * Set the origin patterns to allow. Unlike origins, patterns are more
     * flexible, e.g. "https://*.example.com".
     *
     * @param patterns the origin patterns to allow
     * @return this CorsRegistration for chaining
     */
    public CorsRegistration allowedOriginPatterns(String... patterns) {}

    /**
     * Set the HTTP methods to allow. The special value "*" allows all methods.
     *
     * @param methods the HTTP methods to allow
     * @return this CorsRegistration for chaining
     */
    public CorsRegistration allowedMethods(String... methods) {}

    /**
     * Set the list of headers that a pre-flight request can list as allowed
     * for use during an actual request. The special value "*" allows all headers.
     *
     * @param headers the headers to allow
     * @return this CorsRegistration for chaining
     */
    public CorsRegistration allowedHeaders(String... headers) {}

    /**
     * Set the list of response headers that an actual response might have and
     * can be exposed. The special value "*" allows all headers.
     *
     * @param headers the headers to expose
     * @return this CorsRegistration for chaining
     */
    public CorsRegistration exposedHeaders(String... headers) {}

    /**
     * Whether user credentials are supported.
     *
     * @param allowCredentials whether to allow credentials
     * @return this CorsRegistration for chaining
     */
    public CorsRegistration allowCredentials(boolean allowCredentials) {}

    /**
     * Configure how long, in seconds, the response from a pre-flight request
     * can be cached by clients.
     *
     * @param maxAge the max age in seconds
     * @return this CorsRegistration for chaining
     */
    public CorsRegistration maxAge(long maxAge) {}

    /**
     * Apply the configured CorsConfiguration and return it.
     *
     * @return the CorsConfiguration
     */
    protected CorsConfiguration getCorsConfiguration() {}
}