From 1956b560937724b7380315d5d63bc91396356153 Mon Sep 17 00:00:00 2001 From: Gary Pennington Date: Fri, 26 Aug 2022 11:17:09 +0100 Subject: [PATCH] migrate cors configuration from server to top level (#1586) from: ``` server: cors: ``` to: ``` cors: ``` fixes: #1483 --- NEXT_CHANGELOG.md | 6 + apollo-router/src/axum_http_server_factory.rs | 87 ++++----- apollo-router/src/configuration/mod.rs | 60 +++--- ...se_config_errors_with_inline_sequence.snap | 8 +- ...rs_with_inline_sequence_env_expansion.snap | 8 +- ...e_precise_config_errors_with_sequence.snap | 12 +- ...ig_errors_with_sequence_env_expansion.snap | 12 +- ...nfiguration__tests__schema_generation.snap | 175 ++++++++---------- .../testdata/config_full.router.yaml | 6 +- .../testdata/supergraph_config.router.yaml | 12 +- docs/source/configuration/cors.mdx | 120 ++++++------ .../managed-federation/client-awareness.mdx | 11 +- .../cors-and-csrf/custom-headers.router.yaml | 27 ++- examples/status-code-propagation/router.yaml | 7 +- 14 files changed, 262 insertions(+), 289 deletions(-) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index cf08ae2f3c..e4b291883b 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -27,6 +27,12 @@ By [@USERNAME](https://github.com/USERNAME) in https://github.com/apollographql/ ## ❗ BREAKING ❗ +### Move cors configuration from `server` to top level ([PR #1586](https://github.com/apollographql/router/pull/1586)) + +The cors configuration is now located at the top level of the configuration file. + +By [@garypen](https://github.com/garypen) in https://github.com/apollographql/router/pull/1586 + ### Exit the router after logging panic details ([PR #1602](https://github.com/apollographql/router/pull/1602)) If the router panics, it can leave the router in an unuseable state. diff --git a/apollo-router/src/axum_http_server_factory.rs b/apollo-router/src/axum_http_server_factory.rs index 0d90bb4fb6..ba28ae14e4 100644 --- a/apollo-router/src/axum_http_server_factory.rs +++ b/apollo-router/src/axum_http_server_factory.rs @@ -87,14 +87,9 @@ pub(crate) fn make_axum_router( where RF: SupergraphServiceFactory, { - let cors = configuration - .server - .cors - .clone() - .into_layer() - .map_err(|e| { - ApolloRouterError::ServiceCreationError(format!("CORS configuration error: {e}").into()) - })?; + let cors = configuration.cors.clone().into_layer().map_err(|e| { + ApolloRouterError::ServiceCreationError(format!("CORS configuration error: {e}").into()) + })?; let graphql_endpoint = if configuration.server.endpoint.ends_with("/*") { // Needed for axum (check the axum docs for more information about wildcards https://docs.rs/axum/latest/axum/struct.Router.html#wildcards) format!("{}router_extra_path", configuration.server.endpoint) @@ -1268,14 +1263,14 @@ mod tests { )) }); let conf = Configuration::builder() + .cors( + Cors::builder() + .origins(vec!["http://studio".to_string()]) + .build(), + ) .server( crate::configuration::Server::builder() .listen(SocketAddr::from_str("127.0.0.1:0").unwrap()) - .cors( - Cors::builder() - .origins(vec!["http://studio".to_string()]) - .build(), - ) .endpoint(String::from("/graphql")) .build(), ) @@ -1337,14 +1332,14 @@ mod tests { )) }); let conf = Configuration::builder() + .cors( + Cors::builder() + .origins(vec!["http://studio".to_string()]) + .build(), + ) .server( crate::configuration::Server::builder() .listen(SocketAddr::from_str("127.0.0.1:0").unwrap()) - .cors( - Cors::builder() - .origins(vec!["http://studio".to_string()]) - .build(), - ) .endpoint(String::from("/:my_prefix/graphql")) .build(), ) @@ -1406,14 +1401,14 @@ mod tests { )) }); let conf = Configuration::builder() + .cors( + Cors::builder() + .origins(vec!["http://studio".to_string()]) + .build(), + ) .server( crate::configuration::Server::builder() .listen(SocketAddr::from_str("127.0.0.1:0").unwrap()) - .cors( - Cors::builder() - .origins(vec!["http://studio".to_string()]) - .build(), - ) .endpoint(String::from("/graphql/*")) .build(), ) @@ -1629,10 +1624,10 @@ mod tests { async fn cors_preflight() -> Result<(), ApolloRouterError> { let expectations = MockSupergraphService::new(); let conf = Configuration::builder() + .cors(Cors::builder().build()) .server( crate::configuration::Server::builder() .listen(SocketAddr::from_str("127.0.0.1:0").unwrap()) - .cors(Cors::builder().build()) .endpoint(String::from("/graphql/*")) .build(), ) @@ -1855,14 +1850,14 @@ Content-Type: application/json\r async fn it_doesnt_display_disabled_home_page() -> Result<(), ApolloRouterError> { let expectations = MockSupergraphService::new(); let conf = Configuration::builder() + .cors( + Cors::builder() + .origins(vec!["http://studio".to_string()]) + .build(), + ) .server( crate::configuration::Server::builder() .listen(SocketAddr::from_str("127.0.0.1:0").unwrap()) - .cors( - Cors::builder() - .origins(vec!["http://studio".to_string()]) - .build(), - ) .landing_page(false) .build(), ) @@ -1901,14 +1896,14 @@ Content-Type: application/json\r ); let conf = Configuration::builder() + .cors( + Cors::builder() + .origins(vec!["http://studio".to_string()]) + .build(), + ) .server( crate::configuration::Server::builder() .listen(SocketAddr::from_str("127.0.0.1:0").unwrap()) - .cors( - Cors::builder() - .origins(vec!["http://studio".to_string()]) - .build(), - ) .build(), ) .build(); @@ -2044,10 +2039,10 @@ Content-Type: application/json\r #[tokio::test] async fn cors_allow_any_origin() -> Result<(), ApolloRouterError> { let conf = Configuration::builder() + .cors(Cors::builder().allow_any_origin(true).build()) .server( crate::configuration::Server::builder() .listen(SocketAddr::from_str("127.0.0.1:0").unwrap()) - .cors(Cors::builder().allow_any_origin(true).build()) .build(), ) .build(); @@ -2067,14 +2062,14 @@ Content-Type: application/json\r let valid_origin = "https://thisoriginisallowed.com"; let conf = Configuration::builder() + .cors( + Cors::builder() + .origins(vec![valid_origin.to_string()]) + .build(), + ) .server( crate::configuration::Server::builder() .listen(SocketAddr::from_str("127.0.0.1:0").unwrap()) - .cors( - Cors::builder() - .origins(vec![valid_origin.to_string()]) - .build(), - ) .build(), ) .build(); @@ -2097,15 +2092,15 @@ Content-Type: application/json\r let apollo_subdomains = "https://([a-z0-9]+[.])*apollographql[.]com"; let conf = Configuration::builder() + .cors( + Cors::builder() + .origins(vec!["https://anexactmatchorigin.com".to_string()]) + .match_origins(vec![apollo_subdomains.to_string()]) + .build(), + ) .server( crate::configuration::Server::builder() .listen(SocketAddr::from_str("127.0.0.1:0").unwrap()) - .cors( - Cors::builder() - .origins(vec!["https://anexactmatchorigin.com".to_string()]) - .match_origins(vec![apollo_subdomains.to_string()]) - .build(), - ) .build(), ) .build(); diff --git a/apollo-router/src/configuration/mod.rs b/apollo-router/src/configuration/mod.rs index 51fd6e386f..38184af0a4 100644 --- a/apollo-router/src/configuration/mod.rs +++ b/apollo-router/src/configuration/mod.rs @@ -68,6 +68,10 @@ pub struct Configuration { #[serde(default)] pub(crate) server: Server, + /// Cross origin request headers. + #[serde(default)] + pub(crate) cors: Cors, + /// Plugin configuration #[serde(default)] plugins: UserPlugins, @@ -90,11 +94,13 @@ impl Configuration { #[builder] pub(crate) fn new( server: Option, + cors: Option, plugins: Map, apollo_plugins: Map, ) -> Self { Self { server: server.unwrap_or_default(), + cors: cors.unwrap_or_default(), plugins: UserPlugins { plugins: Some(plugins), }, @@ -246,10 +252,6 @@ pub(crate) struct Server { #[serde(default = "default_listen")] pub(crate) listen: ListenAddr, - /// Cross origin request headers. - #[serde(default)] - pub(crate) cors: Cors, - /// introspection queries /// enabled by default #[serde(default = "default_introspection")] @@ -287,7 +289,6 @@ impl Server { #[allow(clippy::too_many_arguments)] // Used through a builder, not directly pub(crate) fn new( listen: Option, - cors: Option, introspection: Option, landing_page: Option, endpoint: Option, @@ -297,7 +298,6 @@ impl Server { ) -> Self { Self { listen: listen.unwrap_or_else(default_listen), - cors: cors.unwrap_or_default(), introspection: introspection.unwrap_or_else(default_introspection), landing_page: landing_page.unwrap_or_else(default_landing_page), endpoint: endpoint.unwrap_or_else(default_endpoint), @@ -1145,8 +1145,8 @@ server: # The socket address and port to listen on # Defaults to 127.0.0.1:4000 listen: 127.0.0.1:4000 - cors: - allow_headers: [ Content-Type, 5 ] +cors: + allow_headers: [ Content-Type, 5 ] "#, ) .expect_err("should have resulted in an error"); @@ -1161,10 +1161,10 @@ server: # The socket address and port to listen on # Defaults to 127.0.0.1:4000 listen: 127.0.0.1:4000 - cors: - allow_headers: - - Content-Type - - 5 +cors: + allow_headers: + - Content-Type + - 5 "#, ) .expect_err("should have resulted in an error"); @@ -1175,15 +1175,13 @@ server: fn it_does_not_allow_invalid_cors_headers() { let cfg = validate_configuration( r#" -server: - cors: - allow_credentials: true - allow_headers: [ "*" ] +cors: + allow_credentials: true + allow_headers: [ "*" ] "#, ) .expect("should not have resulted in an error"); let error = cfg - .server .cors .into_layer() .expect_err("should have resulted in an error"); @@ -1194,15 +1192,13 @@ server: fn it_does_not_allow_invalid_cors_methods() { let cfg = validate_configuration( r#" -server: - cors: - allow_credentials: true - methods: [ GET, "*" ] +cors: + allow_credentials: true + methods: [ GET, "*" ] "#, ) .expect("should not have resulted in an error"); let error = cfg - .server .cors .into_layer() .expect_err("should have resulted in an error"); @@ -1213,15 +1209,13 @@ server: fn it_does_not_allow_invalid_cors_origins() { let cfg = validate_configuration( r#" -server: - cors: - allow_credentials: true - allow_any_origin: true +cors: + allow_credentials: true + allow_any_origin: true "#, ) .expect("should not have resulted in an error"); let error = cfg - .server .cors .into_layer() .expect_err("should have resulted in an error"); @@ -1307,8 +1301,8 @@ server: # The socket address and port to listen on # Defaults to 127.0.0.1:4000 listen: 127.0.0.1:4000 - cors: - allow_headers: [ Content-Type, "${TEST_CONFIG_NUMERIC_ENV_UNIQUE}" ] +cors: + allow_headers: [ Content-Type, "${TEST_CONFIG_NUMERIC_ENV_UNIQUE}" ] "#, ) .expect_err("should have resulted in an error"); @@ -1325,10 +1319,10 @@ server: # The socket address and port to listen on # Defaults to 127.0.0.1:4000 listen: 127.0.0.1:4000 - cors: - allow_headers: - - Content-Type - - "${TEST_CONFIG_NUMERIC_ENV_UNIQUE:true}" +cors: + allow_headers: + - Content-Type + - "${TEST_CONFIG_NUMERIC_ENV_UNIQUE:true}" "#, ) .expect_err("should have resulted in an error"); diff --git a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_inline_sequence.snap b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_inline_sequence.snap index af90779a4f..8e866d8113 100644 --- a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_inline_sequence.snap +++ b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_inline_sequence.snap @@ -3,11 +3,11 @@ source: apollo-router/src/configuration/mod.rs expression: error.to_string() --- configuration had errors: -1. /server/cors/allow_headers/1 +1. /cors/allow_headers/1 # The socket address and port to listen on # Defaults to 127.0.0.1:4000 listen: 127.0.0.1:4000 - cors: - allow_headers: [ Content-Type, 5 ] - ^----- 5 is not of type "string" +cors: + allow_headers: [ Content-Type, 5 ] + ^----- 5 is not of type "string" diff --git a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_inline_sequence_env_expansion.snap b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_inline_sequence_env_expansion.snap index 8a5c615c54..eb7aa97810 100644 --- a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_inline_sequence_env_expansion.snap +++ b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_inline_sequence_env_expansion.snap @@ -3,11 +3,11 @@ source: apollo-router/src/configuration/mod.rs expression: error.to_string() --- configuration had errors: -1. /server/cors/allow_headers/1 +1. /cors/allow_headers/1 # The socket address and port to listen on # Defaults to 127.0.0.1:4000 listen: 127.0.0.1:4000 - cors: - allow_headers: [ Content-Type, "${TEST_CONFIG_NUMERIC_ENV_UNIQUE}" ] - ^----- "${TEST_CONFIG_NUMERIC_ENV_UNIQUE}" is not of type "string" +cors: + allow_headers: [ Content-Type, "${TEST_CONFIG_NUMERIC_ENV_UNIQUE}" ] + ^----- "${TEST_CONFIG_NUMERIC_ENV_UNIQUE}" is not of type "string" diff --git a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_sequence.snap b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_sequence.snap index d238793d17..9c08888679 100644 --- a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_sequence.snap +++ b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_sequence.snap @@ -3,11 +3,11 @@ source: apollo-router/src/configuration/mod.rs expression: error.to_string() --- configuration had errors: -1. /server/cors/allow_headers/1 +1. /cors/allow_headers/1 listen: 127.0.0.1:4000 - cors: - allow_headers: - - Content-Type - - 5 - ^----- 5 is not of type "string" +cors: + allow_headers: + - Content-Type + - 5 + ^----- 5 is not of type "string" diff --git a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_sequence_env_expansion.snap b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_sequence_env_expansion.snap index 7425ac971c..5c0379c938 100644 --- a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_sequence_env_expansion.snap +++ b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__line_precise_config_errors_with_sequence_env_expansion.snap @@ -3,11 +3,11 @@ source: apollo-router/src/configuration/mod.rs expression: error.to_string() --- configuration had errors: -1. /server/cors/allow_headers/1 +1. /cors/allow_headers/1 listen: 127.0.0.1:4000 - cors: - allow_headers: - - Content-Type - - "${TEST_CONFIG_NUMERIC_ENV_UNIQUE:true}" - ^----- "${TEST_CONFIG_NUMERIC_ENV_UNIQUE:true}" is not of type "string" +cors: + allow_headers: + - Content-Type + - "${TEST_CONFIG_NUMERIC_ENV_UNIQUE:true}" + ^----- "${TEST_CONFIG_NUMERIC_ENV_UNIQUE:true}" is not of type "string" diff --git a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap index 8ba09b3ca6..305334607a 100644 --- a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap +++ b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap @@ -8,6 +8,86 @@ expression: "&schema" "description": "The configuration for the router.\n\nCan be created through `serde::Deserialize` from various formats, or inline in Rust code with `serde_json::json!` and `serde_json::from_value`.", "type": "object", "properties": { + "cors": { + "description": "Cross origin request headers.", + "default": { + "allow_any_origin": false, + "allow_credentials": false, + "allow_headers": [], + "expose_headers": null, + "origins": [ + "https://studio.apollographql.com" + ], + "match_origins": null, + "methods": [ + "GET", + "POST", + "OPTIONS" + ] + }, + "type": "object", + "properties": { + "allow_any_origin": { + "description": "Set to true to allow any origin.\n\nDefaults to false Having this set to true is the only way to allow Origin: null.", + "default": false, + "type": "boolean" + }, + "allow_credentials": { + "description": "Set to true to add the `Access-Control-Allow-Credentials` header.", + "default": false, + "type": "boolean" + }, + "allow_headers": { + "description": "The headers to allow.\n\nIf this value is not set, the router will mirror client's `Access-Control-Request-Headers`.\n\nNote that if you set headers here, you also want to have a look at your `CSRF` plugins configuration, and make sure you either: - accept `x-apollo-operation-name` AND / OR `apollo-require-preflight` - defined `csrf` required headers in your yml configuration, as shown in the `examples/cors-and-csrf/custom-headers.router.yaml` files.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "expose_headers": { + "description": "Which response headers should be made available to scripts running in the browser, in response to a cross-origin request.", + "default": null, + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "match_origins": { + "description": "`Regex`es you want to match the origins against to determine if they're allowed. Defaults to an empty list. Note that `origins` will be evaluated before `match_origins`", + "default": null, + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "methods": { + "description": "Allowed request methods. Defaults to GET, POST, OPTIONS.", + "default": [ + "GET", + "POST", + "OPTIONS" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "origins": { + "description": "The origin(s) to allow requests from. Defaults to `https://studio.apollographql.com/` for Apollo Studio.", + "default": [ + "https://studio.apollographql.com" + ], + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, "csrf": { "description": "CSRF Configuration.", "type": "object", @@ -324,21 +404,6 @@ expression: "&schema" "description": "Configuration options pertaining to the http server component.", "default": { "listen": "127.0.0.1:4000", - "cors": { - "allow_any_origin": false, - "allow_credentials": false, - "allow_headers": [], - "expose_headers": null, - "origins": [ - "https://studio.apollographql.com" - ], - "match_origins": null, - "methods": [ - "GET", - "POST", - "OPTIONS" - ] - }, "introspection": true, "landing_page": true, "endpoint": "/", @@ -348,86 +413,6 @@ expression: "&schema" }, "type": "object", "properties": { - "cors": { - "description": "Cross origin request headers.", - "default": { - "allow_any_origin": false, - "allow_credentials": false, - "allow_headers": [], - "expose_headers": null, - "origins": [ - "https://studio.apollographql.com" - ], - "match_origins": null, - "methods": [ - "GET", - "POST", - "OPTIONS" - ] - }, - "type": "object", - "properties": { - "allow_any_origin": { - "description": "Set to true to allow any origin.\n\nDefaults to false Having this set to true is the only way to allow Origin: null.", - "default": false, - "type": "boolean" - }, - "allow_credentials": { - "description": "Set to true to add the `Access-Control-Allow-Credentials` header.", - "default": false, - "type": "boolean" - }, - "allow_headers": { - "description": "The headers to allow.\n\nIf this value is not set, the router will mirror client's `Access-Control-Request-Headers`.\n\nNote that if you set headers here, you also want to have a look at your `CSRF` plugins configuration, and make sure you either: - accept `x-apollo-operation-name` AND / OR `apollo-require-preflight` - defined `csrf` required headers in your yml configuration, as shown in the `examples/cors-and-csrf/custom-headers.router.yaml` files.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "expose_headers": { - "description": "Which response headers should be made available to scripts running in the browser, in response to a cross-origin request.", - "default": null, - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "match_origins": { - "description": "`Regex`es you want to match the origins against to determine if they're allowed. Defaults to an empty list. Note that `origins` will be evaluated before `match_origins`", - "default": null, - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "methods": { - "description": "Allowed request methods. Defaults to GET, POST, OPTIONS.", - "default": [ - "GET", - "POST", - "OPTIONS" - ], - "type": "array", - "items": { - "type": "string" - } - }, - "origins": { - "description": "The origin(s) to allow requests from. Defaults to `https://studio.apollographql.com/` for Apollo Studio.", - "default": [ - "https://studio.apollographql.com" - ], - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false - }, "endpoint": { "description": "GraphQL endpoint default: \"/\"", "default": "/", diff --git a/apollo-router/src/configuration/testdata/config_full.router.yaml b/apollo-router/src/configuration/testdata/config_full.router.yaml index 56b75532be..0a089aa567 100644 --- a/apollo-router/src/configuration/testdata/config_full.router.yaml +++ b/apollo-router/src/configuration/testdata/config_full.router.yaml @@ -1,5 +1,5 @@ server: listen: 1.2.3.4:5 - cors: - origins: [foo, bar, baz] - methods: [foo, bar] +cors: + origins: [foo, bar, baz] + methods: [foo, bar] diff --git a/apollo-router/src/configuration/testdata/supergraph_config.router.yaml b/apollo-router/src/configuration/testdata/supergraph_config.router.yaml index 42149611ff..cfc6b13cc8 100644 --- a/apollo-router/src/configuration/testdata/supergraph_config.router.yaml +++ b/apollo-router/src/configuration/testdata/supergraph_config.router.yaml @@ -1,8 +1,8 @@ server: listen: "127.0.0.1:4001" - cors: - origins: - - studio.apollographql.com - methods: - - GET - - PUT +cors: + origins: + - studio.apollographql.com + methods: + - GET + - PUT diff --git a/docs/source/configuration/cors.mdx b/docs/source/configuration/cors.mdx index 23e0b7cf63..bd70007ed0 100644 --- a/docs/source/configuration/cors.mdx +++ b/docs/source/configuration/cors.mdx @@ -9,7 +9,7 @@ description: Control browser access to your router > * [Why use CORS?](/apollo-server/security/cors#why-use-cors) > * [Choosing CORS options for your project](/apollo-server/security/cors#choosing-cors-options-for-your-project) -By default, the Apollo Router enables _only_ Apollo Studio to initiate browser connections to it. If your supergraph serves data to other browser-based applications, you need to do one of the following in the `server.cors` section of your router's [YAML config file](./overview/#yaml-config-file): +By default, the Apollo Router enables _only_ Apollo Studio to initiate browser connections to it. If your supergraph serves data to other browser-based applications, you need to do one of the following in the `cors` section of your router's [YAML config file](./overview/#yaml-config-file): * Add the origins of those web applications to the router's list of allowed `origins`. * Use this option if there is a known, finite list of web applications that consume your supergraph. @@ -24,32 +24,30 @@ By default, the Apollo Router enables _only_ Apollo Studio to initiate browser c The following snippet includes an example of each option (use either `allow_any_origin`, or `origins + match_origins`): ```yaml title="router.yaml" -server: - cors: - - # Set to true to allow any origin - # (Defaults to false) - allow_any_origin: true - - # List of accepted origins - # (Ignored if allow_any_origin is true) - # (Defaults to the Apollo Studio url: `https://studio.apollographql.com`) - # - # An origin is a combination of scheme, hostname and port. - # It does not have any path section, so no trailing slash. - origins: - - https://www.your-app.example.com - - https://studio.apollographql.com # Keep this so Apollo Studio can run queries against your router - match_origins: - - "https://([a-z0-9]+[.])*api[.]example[.]com" # any host that uses https and ends with .api.example.com +cors: + + # Set to true to allow any origin + # (Defaults to false) + allow_any_origin: true + + # List of accepted origins + # (Ignored if allow_any_origin is true) + # (Defaults to the Apollo Studio url: `https://studio.apollographql.com`) + # + # An origin is a combination of scheme, hostname and port. + # It does not have any path section, so no trailing slash. + origins: + - https://www.your-app.example.com + - https://studio.apollographql.com # Keep this so Apollo Studio can run queries against your router + match_origins: + - "https://([a-z0-9]+[.])*api[.]example[.]com" # any host that uses https and ends with .api.example.com ``` You can also disable CORS entirely by setting `origins` to an empty list: ```yml title="router.yaml" -server: - cors: - origins: [] +cors: + origins: [] ``` > If your router serves exclusively _non_-browser-based clients, you probably don't need to modify the default CORS configuration. @@ -65,12 +63,11 @@ You can enable credentials with CORS by setting the [`Access-Control-Allow-Crede To allow browsers to pass credentials to the Apollo Router, set `allow_credentials` to `true`, like so: ```yaml {6} title="router.yaml" -server: - cors: - origins: - - https://www.your-app.example.com - - https://studio.apollographql.com - allow_credentials: true +cors: + origins: + - https://www.your-app.example.com + - https://studio.apollographql.com + allow_credentials: true ``` For examples of sending cookies and authorization headers from Apollo Client, see [Authentication](/react/networking/authentication/). @@ -81,39 +78,38 @@ For examples of sending cookies and authorization headers from Apollo Client, se The following snippet shows all CORS configuration defaults for the Apollo Router: ```yaml title="router.yaml" -server: - # - # CORS (Cross Origin Resource Sharing) +# +# CORS (Cross Origin Resource Sharing) +# +cors: + + # Set to true to allow any origin + allow_any_origin: false + + # List of accepted origins + # (Ignored if allow_any_origin is set to true) # - cors: - - # Set to true to allow any origin - allow_any_origin: false - - # List of accepted origins - # (Ignored if allow_any_origin is set to true) - # - # An origin is a combination of scheme, hostname and port. - # It does not have any path section, so no trailing slash. - origins: - - https://studio.apollographql.com # Keep this so Apollo Studio can still run queries against your router - - # Set to true to add the `Access-Control-Allow-Credentials` header - allow_credentials: false - - # The headers to allow. - # Not setting this mirrors a client's received `access-control-request-headers` - # This is equivalent to allowing any headers, - # except it will also work if allow_credentials is set to true - allow_headers: [] - - # Allowed request methods - methods: - - GET - - POST - - OPTIONS - - # Which response headers are available to scripts running in the - # browser in response to a cross-origin request. - expose_headers: [] + # An origin is a combination of scheme, hostname and port. + # It does not have any path section, so no trailing slash. + origins: + - https://studio.apollographql.com # Keep this so Apollo Studio can still run queries against your router + + # Set to true to add the `Access-Control-Allow-Credentials` header + allow_credentials: false + + # The headers to allow. + # Not setting this mirrors a client's received `access-control-request-headers` + # This is equivalent to allowing any headers, + # except it will also work if allow_credentials is set to true + allow_headers: [] + + # Allowed request methods + methods: + - GET + - POST + - OPTIONS + + # Which response headers are available to scripts running in the + # browser in response to a cross-origin request. + expose_headers: [] ``` diff --git a/docs/source/managed-federation/client-awareness.mdx b/docs/source/managed-federation/client-awareness.mdx index 931630a9aa..773fd14203 100644 --- a/docs/source/managed-federation/client-awareness.mdx +++ b/docs/source/managed-federation/client-awareness.mdx @@ -20,9 +20,8 @@ telemetry: client_name_header: MyClientHeaderName # defaults to apollographql-client-version client_version_header: MyClientHeaderVersion -server: - cors: - # The headers to allow. - # (Defaults to [ Content-Type ], which is required for Apollo Studio) - allow_headers: [ Content-Type, MyClientHeaderName, MyClientHeaderVersion] -``` \ No newline at end of file +cors: + # The headers to allow. + # (Defaults to [ Content-Type ], which is required for Apollo Studio) + allow_headers: [ Content-Type, MyClientHeaderName, MyClientHeaderVersion] +``` diff --git a/examples/cors-and-csrf/custom-headers.router.yaml b/examples/cors-and-csrf/custom-headers.router.yaml index 55c8dd234f..e4f1ddc374 100644 --- a/examples/cors-and-csrf/custom-headers.router.yaml +++ b/examples/cors-and-csrf/custom-headers.router.yaml @@ -1,17 +1,16 @@ -server: - cors: - # adding the headers in the CSRF section - # and not here would fail the OPTIONS preflight - # you can: - # - either add them here to be explicit - # - or not set the `allow_headers` key at all. - # the default behavior is `mirror_request`, - # which mirrors the received - # `access-control-request-headers` preflight has sent - allow_headers: - - x-my-custom-required-header - - x-and-an-other-required-header - - content-type # and many more! +cors: + # adding the headers in the CSRF section + # and not here would fail the OPTIONS preflight + # you can: + # - either add them here to be explicit + # - or not set the `allow_headers` key at all. + # the default behavior is `mirror_request`, + # which mirrors the received + # `access-control-request-headers` preflight has sent + allow_headers: + - x-my-custom-required-header + - x-and-an-other-required-header + - content-type # and many more! csrf: # you could set unsafe_disabled: true, but That wouldn't be safe https://developer.mozilla.org/en-US/docs/Glossary/CSRF diff --git a/examples/status-code-propagation/router.yaml b/examples/status-code-propagation/router.yaml index b3ed121b19..a3eda78a0f 100644 --- a/examples/status-code-propagation/router.yaml +++ b/examples/status-code-propagation/router.yaml @@ -1,7 +1,6 @@ -server: - cors: - origins: - - "https://studio.apollographql.com/" +cors: + origins: + - "https://studio.apollographql.com/" plugins: example.propagate_status_code: # Status codes are represented in order,