I have a GraphQL backend with React front-end for an application. The CORS policy is set to only allow the front-end https://my.server:443 to access the backend https://my.server:4444 and it works just fine....most of the time.
My Express.js server is started as follows:
server.start(
{
cors: {
credentials: true,
origin: [ "https://my.server" ]
},
},
(deets) => {
console.log(`Server is now running on port http://localhost:${deets.port}`);
}
);
When I make a POST request to the API with a payload that contains a URL, I get a CORS error. Here is the dialogue:
OPTIONS Request:
OPTIONS / HTTP/2
Host: my.server:4444
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:81.0) Gecko/20100101 Firefox/81.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Referer: https://my.server/qualifications
Origin: https://my.server
Connection: keep-alive
TE: Trailers
Response:
HTTP/2 204 No Content
date: Thu, 15 Oct 2020 12:16:25 GMT
x-powered-by: Express
access-control-allow-origin: https://my.server
vary: Origin, Access-Control-Request-Headers
access-control-allow-credentials: true
access-control-allow-methods: GET,HEAD,PUT,PATCH,POST,DELETE
access-control-allow-headers: content-type
X-Firefox-Spdy: h2
POST Request:
POST / HTTP/2
Host: my.server:4444
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:81.0) Gecko/20100101 Firefox/81.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Content-Length: 616
Origin: https://my.server
Referer: https://my.server/qualifications
Connection: keep-alive
Cookie: token=eyJhbGc<removed-jwt>gmWVO_I68
TE: Trailers
with payload:
{
"operationName": "UPDATE_QUALIFICATION_MUTATION",
"variables": {
"id": "ckf54v5lm0dck07821octvj4b",
"name": "MBA",
"description": "Testing Links",
"link": "http://www.google.com" <---- URL in payload
},
"query": "mutation UPDATE_QUALIFICATION_MUTATION($id: ID!, $name: String, $link: String, $description: String, $company: CompanyUpdateOneInput) {\n updateQualification(where: {id: $id}, data: {name: $name, link: $link, description: $description, company: $company}) {\n id\n name\n description\n link\n company {\n id\n name\n __typename\n }\n __typename\n }\n}\n"
}
Response:
HTTP/2 403 Forbidden
server: awselb/2.0
date: Thu, 15 Oct 2020 12:16:25 GMT
content-type: text/html
content-length: 118
X-Firefox-Spdy: h2
OKAY...let's try this again without the URL this time...
What confuses the heck out of me is that when I do the SAME THING, with the exception of the one field containing a URL - I get this:
OPTIONS Request:
OPTIONS / HTTP/2
Host: my.server:4444
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:81.0) Gecko/20100101 Firefox/81.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Referer: https://my.server/qualifications
Origin: https://my.server
Connection: keep-alive
TE: Trailers
Response:
HTTP/2 204 No Content
date: Thu, 15 Oct 2020 13:07:41 GMT
x-powered-by: Express
access-control-allow-origin: https://my.server
vary: Origin, Access-Control-Request-Headers
access-control-allow-credentials: true
access-control-allow-methods: GET,HEAD,PUT,PATCH,POST,DELETE
access-control-allow-headers: content-type
X-Firefox-Spdy: h2
POST Request:
POST / HTTP/2
Host: my.server:4444
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:81.0) Gecko/20100101 Firefox/81.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Content-Length: 560
Origin: https://my.server
Referer: https://my.server/qualifications
Connection: keep-alive
Cookie: token=eyJhbG<removed-jwt>WVO_I68
TE: Trailers
With payload:
{
"operationName": "UPDATE_QUALIFICATION_MUTATION",
"variables": {
"id": "ckf54v5lm0dck07821octvj4b",
"name": "MBA",
"description": "Testing Links",
"link": "not-a-url" <---- THIS CHANGED
},
"query": "mutation UPDATE_QUALIFICATION_MUTATION($id: ID!, $name: String, $link: String, $description: String, $company: CompanyUpdateOneInput) {\n updateQualification(where: {id: $id}, data: {name: $name, link: $link, description: $description, company: $company}) {\n id\n name\n description\n link\n company {\n id\n name\n __typename\n }\n __typename\n }\n}\n"
}
Response:
HTTP/2 200 OK
date: Thu, 15 Oct 2020 13:07:41 GMT
content-type: application/json
content-length: 173
x-powered-by: Express
access-control-allow-origin: https://my.server
vary: Origin
access-control-allow-credentials: true
X-Firefox-Spdy: h2
Now it works fine?? I am left with more questions than anything else:
- How can the JSON payload of a request affect CORS?
- Is there something missing from my Express server CORS configuration?
- Is there some kind of general issue with sending URL's in the payload?
- If so, is there a suggested workaround? (I was just going to base64 encode/decode it on the front-end, but that seems "wrong" to have to do that!)
Any pointers would be appreciated!