I am developing a client side rendered React web application that has a clearly segregated backend/frontend structure. The backend is a typical graphQL server, and an Apollo graphQL client in the frontend is used to make queries.
When the app was deployed to customers, I started observing an increase in HTTP request failures. The error messages look like below.
In Chrome, Failed to fetch
.
In Firefox, NetworkError when attempting to fetch resource.
.
In Safari, Request header field Content-Type is not allowed by Access-Control-Allow-Headers.
.
Upon inspection on the client side error logs collected, I found that these occurred on pretty old browser versions, e.g. Chrome 49 ~ 58, Firefox 57 and Safari 10 ~ 11.
The issue seems related to CORS and the older browsers seem to have a different behaviour. I tried to extend browser support to such ranges via browserslist but that didn't help.
I landed on posts like this which all talk about adding content-type
to the Access-Control-Allow-Headers
header in the server's response, but I think my situation is a bit different as this only occurs on older browser versions. If my backend were not acting correctly for CORS, it would affect all requests.
I managed to identify the culprit to be the fetch
API used behind the scene by the Apollo graphQL client.
When I tried to reproduce the issue in older browser versions, below error message was observed on the console.
Fetch API cannot load https://account.xxx.com/ap/sso?openid.pape.max_auth_age=3600&signIn...
Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
Apparently the request is being redirected for SSO login. That led to me to suspect that the API was not able to attach the cookies properly when sending in the request, hence no auth token was provided.
This is confirmed on the Fetch API doc that it only changed its default credential policy to same-origin
in August 2017. Hence all browsers released before that won't include cookies unless specified otherwise.
I followed the advanced HTTP networking doc of the Apollo client and included below fetch option, and it started working like a charm.
{ credentials: 'same-origin' }
A side note is that if the policy is set to include
, it poses a stricter limit on the backend server in CORS situations where the Access-Control-Allow-Origin
header cannot be set to wildcard match *
in the HTTP response.
The error message would look like below in such situation.
Access to fetch at 'http://127.0.0.1:1234/graphql' from origin 'http://0.0.0.0:4321' 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’.