Cross-origin Resource Sharing (CORS)

How to enable Cross-origin Resource Sharing (CORS) on a Banyan-secured web service

This article describes features that require Banyan Netagent v1.25.0+.

Banyan Netagent does not directly set CORS response headers (such as Access-Control-Allow-Origin, Access-Control-Allow-Methods etc) to allow selective cross-origin access to a service. Instead, it assumes that the backend application server sets these CORS response headers correctly. Netagent then enables CORS by exempting specific HTTP requests from its TrustCookie check so it may reach the backend server.

Overview

Cross-Origin Resource Sharing (CORS) is a mechanism that allows JavaScript on a web page served on a specific domain, the origin domain, to make XML HTTP Requests (XHR a.k.a AJAX) requests for resources from another domain, the external domain, that is outside the origin domain.

For example, as in the diagram below, a web application served on the origin domain domain-a.com is always allowed make same-origin requests to resources served on domain-a.com. However, requests to resources on the external domain domain-b.com are cross-origin.

If Banyan is used to secure the external domain, cross-origin requests need explicit CORS configurations to work. This is because when a request is made to a Banyan-protected service, Banyan first checks if there is a valid TrustCookie. If an end user accesses a Banyan-protected service on domain-a.com with a valid TrustCookie but has not yet obtained a valid TrustCookie for domain-b.com, then Banyan drops the CORS request for domain-b.com.

Simple and Non-Simple CORS

There are two types of CORS requests - Simple and Preflighted.

  • Simple CORS Requests do not trigger a preflight sequence using the HTTP OPTIONS method.
  • Preflighted CORS Requests trigger a preflight sequence from the browser to the external domain via the HTTP OPTION method. This OPTION preflight sequence established what methods and headers are supported by the external domain.

Most modern CORS scenarios are Preflighted and involve a preflight sequence via the HTTP OPTION method.

CORS With Credentials

By default, browsers do NOT send HTTP Cookies and HTTP Authentication headers when making CORS requests. Most modern CORS scenarios use the Requests With Credentials capability to enhance the security of CORS via authentication. To enable the Requests With Credentials capability, 2 conditions must be met:

  1. The CORS server at the external domain must be configured to allow credentials via the Access-Control-Allow-Credentials header.
  2. The web application at the origin domain must make XHR CORS requests with the withCredentials property set.

The Access-Control-Allow-Credentials header works in conjunction with the XMLHttpRequest.withCredentials property so CORS requests can use credentials such cookies, authorization headers and TLS client certificates.

The HTTP OPTION preflight requests never use HTTP Cookies and HTTP Authentication headers, regardless of whether CORS With Credentials is enabled or not.

Multi-domain Services

In Banyan, multi-domain services refers to the use of a wildcard (*) to create a single service definition that applies to all the subdomains of a higher-level domain. For example, a single service definition for *.foo.example.com would apply to app.foo.example.com, api.foo.example.com, games.foo.example.com, etc. The issued TrustCookie will be valid for all subdomains.

Since many CORS strategies involve a web frontend (e.g., ui.foo.example.com) and an API backend (e.g., api.foo.example.com) served as subdomains, you can leverage Banyan’s multi-domain service capabilities to securely support CORS.


Setup

You can configure Banyan to allow CORS requests by exempting specific HTTP requests from its TrustCookie check, via the OIDC exemptions feature, so CORS requests may reach the backend server.

The sections below details how to enable CORS for most common scenarios. Refer to the HostedService Spec Syntax for a complete description of the OIDC exemption capabilities for use in more advanced scenarios.

1. Multi-Domain Service, CORS With Credentials enabled

In this scenario, the origin domain (e.g., domain-a.foo.example.com) and the external domain (e.g., domain-b.foo.example.com) are both subdomains of a higher-level domain (e.g., foo.example.com). In addition, the CORS server on the external domain has CORS With Credentials enabled.

To configure Banyan to allow this CORS scenario:

  1. Register a Standard Website multi-domain service at *.foo.example.com.

  2. In the Exemptions, select Add CORS Exemption

  3. Configure the CORS Exemption to exempt ORIGIN requests:

The Banyan TrustCookie obtained when the end user browses to the domain-a.foo.example.com origin domain will be scoped to foo.example.com, valid for all subdomains of foo.example.com. We have exempted the ORIGIN requests from the origin domain domain-a.foo.example.com to the external domain domain-b.foo.example.com so the preflight sequence will complete successfully. All subsequent CORS requests to the external domain will use the TrustCookie and will be successfully validated by Netagent.

2. Multi-Domain Service, CORS With Credentials NOT enabled

In this scenario, the origin domain (e.g., domain-a.foo.example.com) and the external domain (e.g., domain-b.foo.example.com) are both subdomains of a higher-level domain (e.g., foo.example.com).

However, the CORS server on the external domain at domain-b.foo.example.com does NOT have CORS With Credentials enabled. Also, the CORS server responds only to GET and POST requests to an API path /api/v1/ when the request contains a valid authentication token submitted via a header called X-Secret-Auth.

Since CORS With Credentials is not enabled, requests to the CORS server will not contain the Banyan-issued TrustCookie. You have to explicitly exempt requests to the CORS server, locked down to the API path.

To configure Banyan to allow this CORS scenario:

  1. Register a Standard Website multi-domain service at *.foo.example.com.

  2. In the Exemptions, select Add CORS Exemption

  3. Configure the CORS Exemption to exempt both ORIGIN requests and requests to the API path:

The Banyan TrustCookie obtained when the end user browses to the domain-a.foo.example.com origin domain. We have exempted the ORIGIN requests from the origin domain domain-a.foo.example.com to the external domain domain-b.foo.example.com so the preflight sequence will complete successfully. We have further exempted API requests from the origin domain to the external domain that contain the X-Secret-Auth header.

3. Single domain Services, CORS With Credentials NOT enabled

In this scenario, the origin domain (e.g., domain-a.foo.example.com) and the external domain (e.g., domain-b.bar.example.com) cannot be covered under the same higher-level domain.

In addition, the CORS server on the external domain at domain-b.bar.example.com does NOT have CORS With Credentials enabled. Also, the CORS server responds only to GET and POST requests to an API path /api/v1/ when the request contains a valid authentication token submitted via a header called X-Secret-Auth. Since CORS With Credentials is not enabled, requests to the CORS server will not contain the Banyan-issued TrustCookie. You have to explicitly exempt requests to the CORS server, locked down to the API path.

To configure Banyan to allow this CORS scenario:

  1. Register a Standard Hosted Website Service for that external domain at domain-b.bar.example.com to which CORS requests are being made

  2. In the Exemptions, select Add CORS Exemption

  3. Configure CORS exemptions to exempt both ORIGIN requests and requests to the API path:

We have exempted the ORIGIN requests from the origin domain domain-a.foo.example.com so the preflight sequence will complete successfully. We have further exempted API requests from the origin domain that contain the X-Secret-Auth header. Note, you can leave the target field in this scenario set to * because this service definition only applies to a single external domain domain-b.bar.example.com.

Last modified: Jul 27, 2021