I am trying to connect my frontend to a secure REST API that requires a custom 'X-API-KEY' header for every request. I am using a standard XMLHttpRequest object, but I'm not sure where in the lifecycle to inject the header so that it isn't rejected by the server. Does the order of calling .open() and .send() matter when using setRequestHeader, and are there certain "forbidden" headers that the browser will block for security reasons?
3 answers
When using the classic XMLHttpRequest object, the absolute rule is that you must call setRequestHeader() after you have called open(), but before you call send(). If you try to set it before opening the connection, the browser will throw an error. For example: xhr.open("POST", url); xhr.setRequestHeader("X-API-KEY", "your_value"); xhr.send(data);. Regarding security, browsers block "Forbidden Header Names" like User-Agent, Referer, and Cookie to prevent request forgery. For modern Software Development, I highly recommend switching to the Fetch API, which handles headers much more cleanly through a dedicated Headers object, making your asynchronous code more readable and easier to debug.
If I am making a cross-origin (CORS) request, do I need to make any specific changes on the server side to allow my custom 'X-API-KEY' header to be read by the script?
You should definitely use the Fetch API instead of XHR. It’s much simpler: just include a headers key in the options object with your custom key-value pairs.
I agree with Kimberly. Fetch is the modern standard. I used it last month to integrate a payment gateway, and being able to pass a new Headers() object made the authentication logic so much cleaner. Tyler, it’s worth the refactor if you’re working on a new project.
Marcus, that is a vital step. When you add a custom header, the browser sends a "preflight" OPTIONS request. Your server must respond to this preflight by including your custom header name in the Access-Control-Allow-Headers response header. If the server doesn't explicitly whitelist 'X-API-KEY', the browser will block the actual POST request for security reasons, even if the header is correctly set in your JavaScript code.