{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/misc/crossing-the-cors-crossroad/",
  "description": "Troubleshoot CORS errors with this practical guide. Learn Access-Control-Allow-Origin headers, preflight requests, and domain allowlisting in Go.",
  "path": "/misc/crossing-the-cors-crossroad/",
  "publishedAt": "2024-03-12T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Networking",
    "Go",
    "Web"
  ],
  "textContent": "Every once in a while, I find myself skimming through the MDN docs to jog my memory on how\n[CORS] works and which HTTP headers are associated with it. This is particularly true when a\nfrontend app can't talk to a backend service I manage due to a [CORS error].\n\nMDN's CORS documentation is excellent but can be a bit verbose for someone just looking for\na way to quickly troubleshoot and fix the issue at hand.\n\nTypically, the CORS issue I encounter boils down to:\n\n- A backend service that accepts requests only from a list of specified domains.\n- A new frontend service or some other client trying to access it from a different domain\n  that's not on the server's allowlist. Consequently, the server rejects it with an HTTP 4xx\n  error.\n\nHere's a list of some commonly found headers associated with CORS:\n\nRequest headers\n\n- Origin: indicates the origin of the request\n- Access-Control-Request-Method: used in [preflight requests] to specify the method of the\n  actual request\n- Access-Control-Request-Headers: used in preflight to specify headers that will be used\n  in the actual request\n\nResponse headers\n\n- Access-Control-Allow-Origin: specifies the origins that are allowed to access the\n  resource\n- Access-Control-Allow-Methods: indicates the methods allowed when accessing the resource\n- Access-Control-Allow-Headers: specifies the headers that can be included in the actual\n  request\n- Access-Control-Allow-Credentials: indicates whether or not the response can be exposed\n  when the credentials flag is true\n- Access-Control-Expose-Headers: specifies the headers that can be exposed as part of the\n  response\n- Access-Control-Max-Age: indicates how long the results of a preflight request can be\n  cached\n\nIn most cases, focusing on the Origin and Access-Control-Allow-Origin headers is enough\nto verify whether a service can be reached from a certain domain without running into a CORS\nerror.\n\nTo recreate the canonical CORS issue, here's a simple server written in Go that exposes a\nsingle POST endpoint /hello. You can make a POST request to it with the\n{\"name\": \"Something\"} payload, and it will echo back with a JSON message.\n\n---\n\n<details>\n\n<summary>Click here ...</summary>\n\n</details>\n\n---\n\nHere, the server only allows requests from two particular domains:\nhttp://allowed-origin-1.com and http://allowed-origin-2.com. A client on another host\ncan make a preflight OPTIONS request to check if the server will permit the subsequent POST\nrequest.\n\nIf the client is on a domain that's not on the allowlist, the server will reject the\nrequest.\n\nYou can run the server with go run main.go and then, from another console, try making a\npreflight request without specifying the Origin header:\n\nThe server will reject this:\n\nYou need to specify one of the domains expected by the server via the Origin header as\nfollows:\n\nThis time, the preflight request will succeed:\n\nNotice that the Access-Control-Allow-Methods header also specifies the methods allowed on\nthis endpoint.\n\nIf you make a preflight request with an origin not on the server's allowlist, you will\nencounter a 4xx error again.\n\nThe return message indicates that requests from http://notallowed.com are blocked by CORS\ncontrol:\n\nSimilarly, making a POST request without sending the expected origin in the header will\nresult in a 4xx error.\n\nThis returns:\n\nLike the preflight request, you need to pass the expected origin in the header.\n\nSo, if your frontend cannot access the backend and the browser console indicates that CORS\ncontrol is blocking the request, you'll likely need to add the new domain to your server's\nallowlist. Then make sure that the client is passing the desired origin in the header. In\nthe case of a browser, this should be automatically handled for you.\n\nUse the preflight request commands to test that the server is only allowing access from the\nwhitelisted domain while blocking everything else.\n\n\n\n\n[cors]:\n    https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS\n\n[cors error]:\n    https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors\n\n[preflight requests]:\n    https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request",
  "title": "Crossing the CORS crossroad"
}