Skip to content

Commit

Permalink
Document the new CORS behavior (#1044)
Browse files Browse the repository at this point in the history
Fixes #1038

This commit updates the CORS documentation to reflect the recent [CORS and CSRF](#1006) updates.
  • Loading branch information
o0Ignition0o authored May 19, 2022
1 parent 9d04643 commit 0684d1f
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 5 deletions.
3 changes: 3 additions & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ Removes the `default` parameter and requires inserted values to implement `Defau
## 🐛 Fixes
## 🛠 Maintenance
## 📚 Documentation
### Add CORS documentation ([PR #1044](https://github.com/apollographql/router/pull/1044))
We've updated the CORS documentation to reflect the recent [CORS and CSRF](https://github.com/apollographql/router/pull/1006) updates.

## 🐛 Fixes
146 changes: 141 additions & 5 deletions docs/source/configuration/cors.mdx
Original file line number Diff line number Diff line change
@@ -1,13 +1,146 @@
---
title: Configuring CORS in the Apollo Router
sidebar_title: CORS
description: Control access to your server's resources
---

import { Link } from 'gatsby';

The Apollo Router supports [Cross-Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) (CORS) to indicate which origins it accepts requests from. **By default, the router accepts requests from the Apollo Studio**.
[Cross-Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) (CORS) is an HTTP-header-based protocol that enables a server to dictate which origins can access its resources. Put another way, your server can specify which websites can tell a user's browser to talk to your server, and precisely which types of HTTP requests are allowed.

If your environment has security requirements around CORS, you can specify them in the router's [configuration file](./overview/#yaml-config-file):
Apollo Router's default CORS behavior enables only the Apollo studio to tell a user's browser to connect to your server.

If your Apollo Router is serving data for web applications, you want to either add it to the list of allowed origins, or switch to `allow_any_origin`.

> ⚠️ If your app is only visible on a private network and uses network separation for security, the default CORS behavior is **not secure**. See [Specifying origins](#specifying-origins) for more information.
By default, websites running on domains that differ from your server's domain can't pass cookies with their requests. For details on enabling cross-origin cookie passing for authentication, see [Passing credentials with CORS](#passing-credentials-with-cors).

## Why use CORS?

Most developers know about CORS because they run into the all-too-common [CORS error](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors). CORS errors usually occur when you set up an API call or try to get your separately hosted server and client to talk to each other. To better understand what CORS is and why we use it, we'll briefly go over some background context.

Internet users should always exercise caution when installing any new software on their devices. But when it comes to browsing the web, we navigate to different sites all the time, letting our browsers load content from those sites along the way. This comes with inherent risks.

As web developers, we don't want a user's browser to do anything fishy to our server while the user is visiting another website. Browser security mechanisms (e.g., CORS or SOP) can give developers peace of mind by enabling a website's server to specify which browser origins can request resources from that server.

The [_origin_](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#definition_of_an_origin) of a piece of web content consists of that content's domain, protocol, and port. The [same-origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) (SOP) is a security mechanism that restricts scripts on one origin from interacting with resources from another origin. This means that scripts on websites can interact with resources from the same origin without jumping through any extra hoops.

If two URLs differ in their domain, protocol, or port, then those URLs come from two different origins:

```bash
# Same origin
http://example.com:8080/ <==> http://example.com:8080/

# Different origin (difference in domain, protocol, and port)
http://example.com:8080/ =X= https://example1.com:8081/
```

However, as we all know, the internet is an exciting place full of resources that can make websites better (importing images, extra fonts, making API calls, and so on). Developers needed a new protocol to relax SOP and safely _share_ resources across different origins.

Cross-Origin Resource Sharing is the mechanism that allows a web page to share resources across different origins. CORS provides an extra layer of protection by enabling servers and clients to define HTTP headers that specify _which_ external clients' scripts can access their resources.

Note that both SOP and CORS are related to [_browser_ security](https://developer.mozilla.org/en-US/docs/Web/Security#security-related_glossary_terms). Neither prevents _other_ types of software from requesting resources from your server.

## Choosing CORS options for your project

When thinking about configuring CORS for your application, there are two main settings to consider:

* Which origins can access your server's resources
* Whether your server accepts user credentials (i.e., cookies) with requests

### Specifying origins

CORS uses [specific HTTP request headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers) as part of its protocol, including [`Access-Control-Allow-Origin`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin). The `Access-Control-Allow-Origin` header (ACAO) enables a server to dictate which origins can use scripts to access that server's resources.

Depending on what you're building, the origins you specify in your CORS configuration might need to change when you're ready to deploy your application.

#### Applications on private networks

If your browser is running your API on a private network (i.e., not on the public internet) and it relies on the privacy of that network for security, we strongly recommend [specifying which origins](#configuring-cors-options-for-apollo-server) can access your server's resources.

> If you instead rely on `allow_any_origin`, while your personal computer is on your private network, a script on any website could potentially make your browser talk to your private API. [Some browsers, such as Chrome, have features under development](https://wicg.github.io/private-network-access/) to solve this problem. But in the meantime, all servers on private networks should *always* specify origins in their CORS configuration.
#### APIs that require cookies

If your API needs to accept [cross-origin cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) with requests, you _must_ specify origins in your CORS configuration. Otherwise, cross-origin cookies are automatically disabled. This is _not_ a security vulnerability, but it does prevent your API from successfully providing cookies.

For examples, see [Passing credentials with CORS](#passing-credentials-with-cors).

#### APIs with known consumers

If you create an API on the public internet to serve resources to your _own_ websites or apps, you want to [specify which origins](#configuring-cors-options-for-apollo-server) can access your server's resources.

#### Public or embedded APIs

If you create a public API or an API to embed in websites you don't control yourself, you probably want to allow _any_ origin to access your server's resources. You can set `allow_any_origin` in your `router.yml` configuration:

```yml
server:
cors:
allow_any_origin: true
```
> Using `allow_any_origin` makes the router send the [wildcard (`*`)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#directives) value for the ACAO header, which enables _any_ website to tell a user's browser to send an arbitrary request (without cookies or other credentials) to your server and read that server's response.

#### APIs with non browser consumers

The default Apollo Server CORS behavior should suit your use case, and https://studio.apollographql.com/sandbox/explorer allows you to run queries against your Apollo Router.
You can always specify origins in your CORS configuration later.

## Configuring CORS options for Apollo Server

By default, the Apollo Router only allows requests from https://studio.apollographql.com. If your Apollo Router is serving data for web applications, you want to either add their origin to the list of allowed origins, or switch to `allow_any_origin`.

> If you need to pass credentials to your server (e.g., via cookies), you can't use the `allow_any_origin` flag. You _must_ provide specific origins. For examples, see [Passing credentials with CORS](#passing-credentials-with-cors).

The Apollo Router has a `cors` section in the yml configuration, which you can use to change your server's default CORS behavior:

```yml
server:
cors:
origins: # ...or set a list of allowed origins
- https://www.your-app.example.com/
- https://studio.apollographql.com/ # So the Apollo studio can still run queries against your router
```

The example above enables CORS requests from `https://www.your-app.example`, along with `https://studio.apollographql.com`.

> Note if you plan to use [Apollo Studio Explorer](https://www.apollographql.com/docs/studio/explorer/explorer/) as a GraphQL web IDE you should include `https://studio.apollographql.com` in your list of valid origins.

To disable CORS entirely, set origins to an empty list:

```yml
server:
cors:
origins: []
```

### Passing credentials with CORS

If your server requires requests to [include a user's credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#requests_with_credentials) (e.g., 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`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials) HTTP header to `true`.

> You *must* [specify an origin](#configuring-cors-options-for-apollo-server) to enable credentialed requests. If your server sends the `*` wildcard value for the `Access-Control-Allow-Origin` HTTP header, your browser will refuse to send credentials.

To enable your browser to pass credentials with the Apollo Router:

1. Use the `cors` section to specify `origins`
2. Set `allow_credentials` to `true`:

```yml
server:
cors:
origins: # ...or set a list of allowed origins
- https://www.your-app.example.com/
- https://studio.apollographql.com/ # So the Apollo studio can still run queries against your router
allow_credentials: true
```

For examples of sending cookies and authorization headers from Apollo Client, see [Authentication](/react/networking/authentication/).

Here's a summary of all the supported CORS configuration:

```yaml title="router.yaml"
server:
Expand All @@ -24,15 +157,18 @@ server:
# (Ignored if allow_any_origin is true)
# (Defaults to the Apollo Studio url: `https://studio.apollographql.com`)
origins:
- https://www.my-frontend.com
- https://www.your-app.example.com/
- https://studio.apollographql.com/ # So the Apollo studio can still run queries against your router

# Set to true to add the `Access-Control-Allow-Credentials` header
# (Defaults to false)
allow_credentials: true

# The headers to allow.
# (Defaults to [ Content-Type ], which is required for Apollo Studio)
allow_headers: [ Content-Type, Authorization ]
# If this field is not set, CORS will default to the `mirror_request` mode,
# which mirrors the received `access-control-request-headers`
# (This is equivalent to allowing any headers)
allow_headers: [ Content-Type, Authorization, x-my-custom-required-header, x-and-an-other-required-header ]

# Allowed request methods
# (Defaults to [ GET, POST, OPTIONS ])
Expand Down

0 comments on commit 0684d1f

Please sign in to comment.