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.