@@ -947,6 +947,8 @@ Built-in helpers:
947947 classpath resource or filesystem file (content-type inferred from extension; the stream is
948948 opened and closed per request, and the handler owns its lifecycle). Throws
949949 ` IllegalArgumentException` at construction if the resource or file is missing.
950+ - ` Handlers.corsPreflightHandler(...)` — answers CORS `OPTIONS` preflight requests against
951+ caller-supplied allowlists. See [CORS preflight](#cors-preflight) below.
950952
951953# ## Wildcards in extra routes
952954
@@ -1015,6 +1017,31 @@ empty dependency list; the exception never reaches the configured `ExceptionHand
10151017`HEAD` are accepted; other methods return `405 Method Not Allowed` with an `Allow : GET, HEAD`
10161018header.
10171019
1020+ # ## CORS preflight
1021+
1022+ ` Handlers.corsPreflightHandler(...)` answers `OPTIONS` preflight requests so browsers can
1023+ perform cross-origin calls against the server. The handler is preflight-only — wire it on a
1024+ wildcard `extraRoute` covering the routes you want to expose to browsers.
1025+
1026+ ` ` ` java
1027+ var server = OpenApiServer.builder()
1028+ .spec(spec)
1029+ .handlers(handlers)
1030+ .extraRoute("/api/**", Handlers.corsPreflightHandler(
1031+ List.of("https://app.example.com"),
1032+ List.of(GET, POST, PUT, DELETE),
1033+ List.of("content-type", "authorization"),
1034+ true, // Access-Control-Allow-Credentials
1035+ Duration.ofMinutes(10))) // Access-Control-Max-Age
1036+ .build();
1037+ ` ` `
1038+
1039+ For dynamic origin policy (regex match, suffix match, tenant lookup) pass a `Predicate<String>`
1040+ instead of a `List<String>`. Allowed-headers comparison is case-insensitive. Disallowed origins,
1041+ methods, or headers return `403` with no CORS headers (the browser then blocks the request);
1042+ non-`OPTIONS` requests return `405` with `Allow : OPTIONS`; preflights missing the `Origin` or
1043+ ` Access-Control-Request-Method` header return `400`.
1044+
10181045# # End-to-end example
10191046
10201047Gson on the classpath for request/response JSON, SnakeYAML on the classpath for the spec, one
0 commit comments