Rate this page

Making cross-domain requests with CORS

All web browsers have a security feature called the same-origin policy. This policy prevents client-side scripts from accessing data from a URL that does not share the same origin. If your application needs to make requests to the Data Governance Broker’s APIs from a client-side script, then you or your administrator must configure a CORS policy on the Data Governance Broker to safely work with the same-origin policy.

This article will introduce you to CORS so that you can understand how to appropriately configure CORS on the Data Governance Broker.

Web origins

But first, what is an origin? A web origin is a triple consisting of:

  1. The protocol scheme (e.g., ‘http’ or ‘https’)
  2. The host
  3. The port

If two URLs have the same origin, then they pass the same-origin policy. Let’s look at some examples. In each URL, the origin is boldfaced.

URL A URL B Same origin?
http://example.com/a http://example.com/b yes
http://example.com/a http://example.com:8080/b no
http://example.com/a https://example.com/b no
http://example.com/a http://www.example.com/b no

As you can see, the URL path is not part of an origin, and hosts must match exactly.

CORS

On to CORS itself. In the past, client-side code was primarily used to enhance a web application’s user interface, but it is increasingly common to need to call on external services. This has created a need to relax the same-origin policy without throwing it out altogether.

CORS, or cross-origin resource sharing, is a W3C standard defining a mechanism by which a service can instruct a browser that it should allow requests from different origins.

If you aren’t interested in details about CORS, you may want to skip down to Configuring CORS policies.

Simple requests

There are certain request types that a browser should already be able to make without CORS. These are requests using the GET, HEAD, or POST methods with the following headers:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type, if the value is one of the following:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Under CORS, the browser also adds an Origin header to one of these requests. If the server is configured to support CORS and accepts the origin value provided by the browser, then it will add the following headers to its response:

Response header Description
Access-Control-Allow-Origin A single-valued header consisting of the Origin value supplied by the browser, or *, indicating that all Origins are accepted.
Access-Control-Allow-Credentials A single-valued boolean header indicating whether or not the server will accept cookies and/or HTTP authentication information.
Access-Control-Expose-Headers A comma-delimited, multi-valued header providing a list of response headers that may be exposed to the client.

Requests requiring preflight

For requests that do not meet the criteria of a simple request, the browser will execute two requests, a preflight request, and the actual request.

The preflight request allows the browser to essentially check for permission to perform a request before actually performing it. It’s made as an OPTIONS request with the following headers:

Request header Description
Origin The web origin of the requesting page.
Access-Control-Request-Method The HTTP method that will be used for the actual request.
Access-Control-Request-Headers A comma-delimited, multi-valued header providing a list of the request headers that the browser will send with the actual request.

If the Data Governance Broker is configured to support CORS, then it will return a 200 response with the following headers:

Response header Description
Access-Control-Allow-Origin A single-valued header consisting of the Origin value supplied by the browser, or *, indicating that all Origins are accepted.
Access-Control-Allow-Methods A comma-delimited, multi-valued header providing a list of the HTTP methods accepted by the server.
Access-Control-Allow-Headers A comma-delimited, multi-valued header providing a list of request headers accepted by the server.
Access-Control-Allow-Credentials A single-valued boolean header indicating whether or not the server will accept cookies and/or HTTP authentication information.
Access-Control-Max-Age A numeric value indicating the number of seconds before the preflight response should be considered stale. This gives the browser a way of caching preflight responses.

If the server does not respond as above, then the browser considers the response a denial of the preflight request. (When CORS problems occur, they typically happen at this point. You should use your browser’s developer tools to look for a 403 response to an OPTIONS request.)

Finally, the browser may make the actual request, providing an Origin header along with anything it would normally provide. The server will respond by adding an Access-Control-Allow-Origin header to the response it normally would make. The browser then checks for a match to determine if the client-side script should receive the response.

Configuring CORS policies

The above introduction provided some necessary background that should help you to understand what you’re doing as you configure a CORS policy on the Data Governance Broker.

The actual configuration procedure is simple. You need to do two things:

  1. Create an HTTP Servlet Cross Origin Policy. This defines a set of criteria for accepting requests from another origin.
  2. Assign the CORS policy to one or more HTTP Servlet Extensions. These HTTP servlet extensions correspond to the services that your client will use. Example HTTP servlet extensions are SCIM2, UserInfo Servlet, OAuth2 Servlet, and JWK Servlet.

Let’s look at an example. In this example, we are going to create a CORS policy that allows a specific client to make various CRUD requests against the Data Governance Broker’s SCIM 2 service.

First, we create the CORS policy.

dsconfig create-http-servlet-cross-origin-policy --policy-name "My App" \
  --set cors-allowed-methods:DELETE \
  --set cors-allowed-methods:GET \
  --set cors-allowed-methods:POST \
  --set cors-allowed-methods:PUT \
  --set cors-allowed-methods:PATCH \
  --set cors-allowed-headers:Accept \
  --set cors-allowed-headers:Access-Control-Request-Headers \
  --set cors-allowed-headers:Access-Control-Request-Method \
  --set cors-allowed-headers:Authorization \
  --set cors-allowed-headers:Content-Type \
  --set cors-allowed-headers:Origin \
  --set cors-allowed-headers:X-Requested-With \
  --set cors-enable-per-application-origins:true

Note the cors-enable-per-application-origins property. This indicates that the origins allowed by this CORS policy will be defined elsewhere, in the application configuration.

So we next need to update the application’s configuration to declare its web origin.

dsconfig set-oauth2-client-prop --client-name "My App" \
  --set trusted-cors-origin:https://my-app.com

Finally, we assign the CORS policy to the SCIM 2 service.

dsconfig set-http-servlet-extension-prop --extension-name SCIM2 \
  --set "cross-origin-policy:My App"