CORS error while using xmlHttpRequest

When I try to make a request using the sample code, be it GET or POST, I get this error message.

origin ‘http://localhost:8080’ 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’. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

If I set xhr.withCredentials = false, I get an error related to Http status

origin ‘http://localhost:8080’ has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.

I have been using headers: content-type text/plain just to get my GET requests working. But I am not able to use text/plain for POST requests.

Any help will be appreciated. Thank you.

Hi @bdwly - which sample code are you using? Which requests? Which endpoints?

Side note, mailsac has a REST API which always returns JSON. So the mime type is application/json not text/plain. Unless you’re fetching an individual email message’s text body.

Hi @ruffrey thank you for your response.

Apologies for failing to furnish my post with more details. I was referring to the sample javascript code as provided in the API. It basically happens to all endpoints and requests as far as I can tell. One example would be as follows:

endpoint: https://mailsac.com/api/outgoing-messages
request: POST
Sample code used(with removal of some unused object properties):

const data = JSON.stringify({
  "to": "[email protected]", // I replaced this with my gmail address during testing
  "from": "[email protected]",
  "subject": "string",
  "text": "string",
  "html": "string"
});

const xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://mailsac.com/api/outgoing-messages");
xhr.setRequestHeader("content-type", "application/json");
xhr.setRequestHeader("Mailsac-Key", "REPLACE_KEY_VALUE");

xhr.send(data);

setting xhr.withCredentials = true;
returns

origin ‘http://localhost:8080/ 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’. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

and

setting xhr.withCredentials = false;

returns

origin http://localhost:8080/ has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.

I hope this better helps you help me with my issues. Thanks again for your help.

Hello, thanks for the additional details, that helps a lot.

First thing is that I don’t think you need xhr.withCredentials set, because my understanding is this is a cookie-related thing. Your authentication key to mailsac is set as the header mailsac-key.

However based on the error message, it looks like you are doing requests directly to mailsac from a web browser. All of our JavaScript examples assume it’s a Node.js server, for two reasons. First one is the CORS issue you are seeing. The second reason is security.

For the most part, only browsers care about CORS, to protect users. Servers won’t care. Which means you would be storing the mailsac-key in source control or otherwise plaintext and giving it to the user. I can explain in more detail.

Typically what people do is store the secret mailsac-key on a backend server, and use a server (Node.js) to proxy these requests to Mailsac. Then on the frontend you can authenticate your users and store a temporary session on their browser cookies or localStorage. This way you protect the mailasc-key and can limit what a user in the browser can do against mailsac. For example if you only wanted to allow checking email for a specific address for a specific user, you could control that on your backend server. By setting up the app the way you did, any particular user of your app can do anything on mailsac - check any other user’s email, delete all your private forwarding rules, and more.

I may be telling you something you already know! Perhaps your app is running inside your company’s private network/intranet, or accessible via vpn only.

So if all you wanted to do is proxy every request through a backend, it might look something like this in Node.js:

untested proxy example

const express = require('express')
const expressHttpProxy = require('express-http-proxy')

const app = express()

const MAILSAC_KEY = process.env.MAILSAC_KEY // env var you need to set

app.use('/mailsac', expressHttpProxy('mailsac.com', {
  proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
      // intercept every proxied request, adding auth header
      proxyReqOpts.headers['Mailsac-Key'] = MAILSAC_KEY;
      return proxyReqOpts;
    }
));

Now every request a user makes at this server at /mailsac/* would be proxied to mailsac.com. For example to get the mail for an address [email protected] your user make the following request to your server:

GET /mailsac/api/addresses/[email protected]/messages

A final note - there really is no other way to get around these CORS issues in the way you are attempting. Otherwise when you visit any random blog website, nothing would prevent that blog from running JavaScript to go check if you are logged into Facebook.com and your bank, and steal your facebook account and money. Web browsers enforce CORS in an increasingly specific and strict way, so they can protect against these sorts of attacks.

1 Like

Thank you for your clarification. I was using it for some basic test and verification through the browser but I will move my process to the server in this case. Thank you for your help.