Configuring CORS

Control browser access to your router


note
This article describes CORS configuration that's specific to the GraphOS Router and Apollo Router Core. For a more general introduction to CORS and common considerations, see the following sections:

By default, the router enables only GraphOS 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:

  • Add the origins of those web applications to the router's list of allowed policies.

    • Use this option if there is a known, finite list of web applications that consume your supergraph.

  • Add a regex that matches the origins of those web applications to the router's list of allowed policies.

    • This option comes in handy if you want to match origins against a pattern, see the example below that matches subdomains of a specific namespace.

  • Enable the allow_any_origin option.

    • Use this option if your supergraph is a public API with arbitrarily many web app consumers.

    • With this option enabled, the router sends the wildcard (*) value for the Access-Control-Allow-Origin header. This enables any website to initiate browser connections to it (but they can't provide cookies or other credentials).

  • If clients need to authenticate their requests with cookies, you must use either origins, match_origins, or the combination of both options. When using both options, note that origins is evaluated before match_origins.

The following snippet includes an example of each option (use either allow_any_origin, or origins and/or match_origins):

YAML
router.yaml
1cors:
2
3  # Set to true to allow any origin
4  # (Defaults to false)
5  allow_any_origin: true
6
7  # List of accepted origins
8  # (Ignored if allow_any_origin is true)
9  # (Defaults to the GraphOS Studio url: `https://studio.apollographql.com`)
10  #
11  # An origin is a combination of scheme, hostname and port.
12  # It does not have any path section, so no trailing slash.
13  policies:
14    - origins:
15        - https://www.your-app.example.com
16        - https://studio.apollographql.com # Keep this so GraphOS Studio can run queries against your router
17      match_origins:
18        - "^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 policies to an empty list:

yml
router.yaml
1cors:
2  policies: []

If your router serves exclusively non-browser-based clients, you probably don't need to modify the default CORS configuration.

Passing credentials

If your router requires requests to include a user's credentials (e.g., via cookies), you need to modify your CORS configuration to tell the browser those credentials are allowed.

You can enable credentials with CORS by setting the Access-Control-Allow-Credentials HTTP header to true.

To allow browsers to pass credentials to the router, set allow_credentials to true, like so:

YAML
router.yaml
1cors:
2  policies:
3    - origins:
4        - https://www.your-app.example.com
5        - https://studio.apollographql.com
6  allow_credentials: true
tip
To support credentialed requests, your router's config file must specify individual origins. If your router enables allow_any_origin, your browser will refuse to send credentials.

Additionally, you'll need to configure the router to forward the Cookie header to some (or all) of your subgraphs:

YAML
router.yaml
1headers:
2  all:
3    request:
4      - propagate:
5          named: cookie

For examples of sending cookies and authorization headers from Apollo Client, see Authentication.

CORS private network access

By default, browsers block any requests sent to a device or service on a private network. If your router requires requests to a device or service on a private network, you need to enable this behavior in your CORS configuration.

To enable private network access with CORS, your router must return the Access-Control-Allow-Private-Network HTTP header with a value of true. To do so, add the private_network_access with an empty access_id value in the policies of your cors config.

YAML
router.yaml
1cors:
2  policies:
3    - origins:
4        - https://www.your-app.example.com
5        - https://studio.apollographql.com
6      private_network_access:
7        access_id:

Optionally, you can specify the access_id and access_name subfields to identify what is being accessed in the private network when the browser prompts the user for permission. These fields return the Private-Network-Access-ID and Private-Network-Access-Name HTTP headers, respectively, along with the specified strings.

YAML
router.yaml
1cors:
2  policies:
3    - origins:
4        - https://www.your-app.example.com
5        - https://studio.apollographql.com
6      private_network_access:
7        access_id: "01:23:45:67:89:0A"
8        access_name: "mega-corp device"

Policy inheritance

Individual policies within the policies array inherit global CORS settings unless explicitly overridden:

  • Allow credentials: Policies inherit the global allow_credentials setting unless they specify their own value

  • Allow headers: Policies inherit global headers if their allow_headers is empty, otherwise use policy-specific headers

  • Expose headers: Policies inherit global headers if their expose_headers is empty, otherwise use policy-specific headers

  • Methods: Policies have three inheritance states:

    • Not specified (null): Inherits global methods

    • Empty array ([]): No methods allowed for this policy

    • Specific values: Uses those exact methods

  • Max age: Policies inherit the global max_age unless they specify their own value

All cors options

The following snippet shows all CORS configuration defaults for the router:

YAML
router.yaml
1#
2# CORS (Cross Origin Resource Sharing)
3#
4cors:
5
6  # Set to true to allow any origin
7  allow_any_origin: false
8
9  # List of accepted origins
10  # (Ignored if allow_any_origin is set to true)
11  #
12  # An origin is a combination of scheme, hostname and port.
13  # It does not have any path section, so no trailing slash.
14  policies:
15    - origins:
16        - https://studio.apollographql.com # Keep this so GraphOS Studio can still run queries against your router
17      # Enable private network access for the router
18      private_network_access:
19        access_id:
20
21  # Set to true to add the `Access-Control-Allow-Credentials` header
22  allow_credentials: false
23
24  # The headers to allow.
25  # Not setting this mirrors a client's received `access-control-request-headers`
26  # This is equivalent to allowing any headers,
27  # except it will also work if allow_credentials is set to true
28  allow_headers: []
29
30  # Allowed request methods
31  methods:
32    - GET
33    - POST
34    - OPTIONS
35
36  # Which response headers are available to scripts running in the
37  # browser in response to a cross-origin request.
38  expose_headers: []
39
40  # Adds the Access-Control-Max-Age header
41  # Can be set to a duration in time units
42  # If not set, the header is not included
43  max_age: 2h

Response Vary header

A plugin may set a response Vary header. If, after all plugins are processed, there is no response Vary header, then the router will add one with a value of "origin".

Feedback

Edit on GitHub

Ask Community