GraphQL CORs preflight endpoint configuration

During testing for an upgrade to 10.2 of a JSS implementation recently we identified that some of our connected GQL calls were failing when running locally in the client due to CORs issues.

Access to fetch at 'https://mysitecoreinstance.com/api/my-web-gql-endpoint' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.

Previously these had just worked OOTB assuming the API keys were all correctly set. As the error indicates, this only occurs when making requests “withCredentials” (this could be cookies, headers etc) on the preflight and the response contains a wildcard rather than a specific value. In our previous implementation (on Sitecore 9.3/JSS 13) the preflight response of the ‘Access-Control-Allow-Origin’ header was returning the values specified in the API keys as expected, but 10.2/JSS 19 endpoints were always returning the wildcard, irrelevant of values or even if the key was valid!

A little peeking into the code showed me that GraphQL endpoints now have an additional property (AllowUnauthenticatedCorsPreflight) that will allow preflight CORs calls to skip authentication on GQL controller endpoints and return a blanket wildcard with the following headers:

      response.AddHeader("Access-Control-Allow-Origin", "*");
      response.AddHeader("Access-Control-Allow-Headers", "*");
      response.AddHeader("Access-Control-Max-Age", "10");

By default the AllowUnauthenticatedCorsPreflight property is set to true, which explains why all of our preflight calls in the scenario above started failing. Easy fix was to identify which GraphQL endpoints actually required authentication (anything using withCredentials) and add the AllowUnauthenticatedCorsPreflight element to the configuration and set the value to false:

<MyWebAppGraphQLEndpoint url="/api/my-web-gql-endpoint" type="Sitecore.Services.GraphQL.Hosting.DatabaseAwareGraphQLEndpoint, Sitecore.Services.GraphQL.NetFxHost" resolve="true">
	<url>$(url)</url>
	<enabled>true</enabled>
	<enableSubscriptions>false</enableSubscriptions>
						
	<!--Added in 10.2 to ensure cors preflight calls are authed and use API key values-->
	<AllowUnauthenticatedCorsPreflight>false</AllowUnauthenticatedCorsPreflight>
            
	<!-- lock down the endpoint when deployed to content delivery -->
	<graphiql role:require="ContentDelivery">false</graphiql>
	<enableSchemaExport role:require="ContentDelivery">false</enableSchemaExport>
	<enableStats role:require="ContentDelivery">false</enableStats>
	<enableCacheStats role:require="ContentDelivery">false</enableCacheStats>
	<disableIntrospection role:require="ContentDelivery">true</disableIntrospection>
.......
All the other things
.......
</MyWebAppGraphQLEndpoint>

This will ensure that all calls to this endpoint, including CORs preflights, are authenticated in the same way, perhaps at the cost of some performance. In a lot of cases, the default settings will suffice, but can see this as a breaking change (which presents as a front end issue) that some may hit in their upgrade adventures.

One thought on “GraphQL CORs preflight endpoint configuration

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s