Request blocked by CORS policy only when app is hosted in Firebase - firebase

My Flutter web app needs to call an API when the user submits a contact form. The API is that of a discord bot that proceeds to post the message in a specific channel on my Discord server. This setup works fine for two other apps that are using the same dependencies and the same production environment (Firebase hosting), but on this specific app it throws the following error:
Access to XMLHttpRequest at
'https://discordapp.com/api/channels/689799838509957177/messages' from
origin 'https://autonet.tk' has been blocked by CORS policy: Response
to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
If I add the header 'Access-Control-Allow-Origin': '*' to the request, I just get a XMLHttpRequest error
My code:
import 'package:http/http.dart' as http;
var resp = await http.post(
"https://discordapp.com/api/channels/689799838509957177/messages",
headers: {
'Authorization': "Bot " + botToken,
},
body: {
"content": "NEW MESSAGE: " + body
});
Making it harder to triangulate the root cause is the fact that this runs fine on my local machine. It's only once I deploy the app to Firebase hosting that I get that CORS error.
Another thing worth noting is that on the Discord side, there is no configuration that I had to make in order to accept the incoming request for the other two web apps that work fine using the same code. (There is no list of allowed hosts).

'Access-Control-Allow-Origin' it's a header that must be in the response, not in the request. For more information, I suggest you this read:
https://stackoverflow.com/a/20035319/14106548
EDIT:
After a small research I think you are calling the wrong endpoint. This is why the response doesn't have the proper header attached.
The endpoint is:
https://discord.com/api
For more info look at: https://discord.com/developers/docs/reference

Related

NextJS - fetch() works only inside getServerSideProps()

My fetch() method for making api requests works only when inside getServerSideProps() method.
For example I have api call for fetching a customer cart (and it is inside getServerSideProps):
const res = await fetch(apiUrl, {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + jwtToken
}
});
And it works fine, I get response from api with customer cart. But when I try to make that api call on a button click, and when I move that inside button click handle method, then I get firstly:
Access to fetch at '...' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
After that when I set mode to 'no-cors', then I get this:
GET ... net::ERR_ABORTED 400 (Bad Request)
So how it is possible that when inside getServerSideProps, there are no any CORS issues and everything is good, but when works on a button click then I get CORS issue and after that there is that other 'Bad request' problem.
Becuase by design browsers block the API request when the API response doesn't have Access-Control-Allow-Headers. But when you fetch the API inside getServerSideProps the the API request is made by Node.js server which doesn't check for Access-Control-Allow-Headers.
If you want to make this API request in browser then you can fix it by:
// If you can change the API code, here's an example to add the CORS headers in a netlify serverless function, this is the API response that I return from a serverless function
return {
statusCode: 200,
headers: {
/* Required for CORS support to work */
'Access-Control-Allow-Origin': '*', // you can add the domain names here or '*' will allow all domains
/* Required for cookies, authorization headers with HTTPS */
'Access-Control-Allow-Credentials': true
},
body: JSON.stringify({
message: 'Hello from netlify'
})
}
or If your API backend is in Node.js and Express.js you can use cors npm package
if you don't have the access to change the API then try writing a wrapper API (or you can say a proxy API) that will make the API request and send it's response to you.
or If you just want the API request to happen for once only (on page load like componentDidMount) you can use the getServerSideProps.
For more detailed explanation on how to fix CORS error read
How does Access-Control-Allow-Origin header work?

Sec-Fetch-Mode instead of Preflight

I created login FE and finished it.
And as per usual my goto for ajax was Axios. My code is as follows.
const baseUrl = http://localhost:5000/project/us-central1/api
Axios.post(
`${baseUrl}/v1/user/login`,
{ ...data },
{
headers: {
Authorization: 'Basic auth...'
}
},
).then(r => console.log(r).catch(e =>console.log(e));
Now when i try to send request to my local firebase cloud function.
I get a 400 bad request.
after checking the request, I was wondering why it wasn't sending any preflight request, which it should do(to the best of my knowledge) but instead I saw a header named Sec-Fetch-Mode. I searched anywhere it's a bit abstract. And I can't seem to figure anything why my request still fails.
Is there anything Im missing in my config of axios?
My FE is running on a VSCode Plugin named live server(http://127.0.0.1:5500)
Also, my firebase cloud function has enabled cors
// cloud function expres app
cors({
origin: true
})
Any insights would be very helpful.
The OPTIONS request is actually being sent, because you are sending a cross-origin request with an Authorization header which is considered as non-simple. It doesn't show in developer tools because of a feature/bug in Chrome 76 & 77. See Chrome not showing OPTIONS requests in Network tab for more information.
The preflight request is a mechanism that allows to deny cross-origin requests on browser side if the server is not CORS aware (e.g: old and not maintained), or if it explicitly wants to deny cross-origin requests (in both cases, the server won't set the Access-Control-Allow-Origin header). What CORS does could be done on server side by checking the Origin header, but CORS actually protects the user at browser level. It blocks the disallowed cross-origin requests even before they are sent, thus reducing the network traffic, the server load, and preventing the old servers from receiving any cross-origin request by default.
On the other hand, Sec-Fetch-Mode is one of the Fetch metadata headers (Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site and Sec-Fetch-User). These headers are meant to inform the server about the context in which the request has been sent. Based on this extra information, the server is then able to determine if the request looks legitimate, or simply deny it. They exist to help HTTP servers mitigate certain types of attacks, and are not related to CORS.
For example the good old <img src="https://mybank.com/giveMoney?amount=9999999&to=evil#attacker.com"> attack could be detected on server side because the Sec-Fetch-Dest would be set to "image" (this is just a simple example, implying that the server exposes endpoints with the GET method with unsafe cookies for money operations which is obviously not the case in real life).
As a conclusion, fetch metadata headers are not designed to replace preflight requests, but rather to coexist with them since they fulfill different needs. And the 400 error has likely nothing to do with these, but rather with the request that does not comply with the endpoint specification.
You are missing a dot on your spread operator, this is the correct syntax:
{ ...data }
Note the three dots before “data”.
Please see the use of spread operators with objects here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

How can I get my express server to redirect the client to a different domain using cors?

I have an express server that already has cors middlewear enabled.
https://myapi.com
app.use(cors({ origin: true }));
I have a single page application that makes a request and is suppose to get redirect to paypal after. (It gets served from a different origin as listed below)
https://myAngularApp.com (some service)
http.post('https://myapi.com/create-payment', data);
So back in in the express server, I want to send them off to paypal for authentication:
app.post('/create-payment', (req, res) => {
res.redirect('https://www.sandbox.paypal.com/somewhere..');
})
Back in the client I get the following error:
Failed to load https://www.sandbox.paypal.com/somewhere: Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.
Looking at the request my client makes to paypal, you can also see that the origin is null.
(Just to note, disabling app.use(cors({ origin: true })); won't allow the client to get a normal response from the server, so this already shows that the cors middleware is linked up.
Error when commenting out cors
// app.use(cors({ origin: true })); - Commented Out
Failed to load "https://myapi.com/create-payment": Redirect from
'https://myapi.com/create-payment' to
'https://www.sandbox.paypal.com/somewhere.' has been blocked by CORS
policy: No 'Access-Control-Allow-Origin' header is present on the
requested resource. Origin 'https://myAngularApp.com' is therefore not
allowed access.
What else do I need to setup on the express server so that the client can be redirected to paypal?
Redirects work like this:
Client makes HTTP request
Server makes HTTP response that includes an instruction to request a different URL
Client makes HTTP request to the different URL
Server (possibly a different server) makes HTTP response
If, at step 2, the server grants permission to read the response via CORS, then that grants permission for that request.
There is no way for the response at step 2 (which is being made by your server) to grant permission to read the response at step 4 (which is being made by PayPal's server).
If Paypal doesn't grant permission with CORS, then your JavaScript cannot read the response.
(Just imagine if that weren't the case: EvilHacker.Net grants permission with CORS, then redirects to GMail.com, and then EvilHacker can read all your email!)

GoogleMapsclient NPM errors on client not on server

When I run this code on client side instead of server it returns the error. If it is run on the server it works fine. I'm using meteor. I'm struggling to find a solution online. Can someone explain what I'm doing wrong here?
Path: Code on client
googleMapsClient.geocode({
address: 'My test address'
}, function(err, response) {
if (!err) {
console.log(response.json.results);
}
});
Error: in console
Failed to load https://maps.googleapis.com/maps/api/geocode/json?address=Test%20address&key=MYKEY: 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'. Origin 'http://localhost:3000' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
This seems to be answered by the author of the library here. It's a good idea to first go through the github issues for a given library in order to find common mistakes. The idea is that the library is supposed to be used on the server side, for the client side use you would use google's API.

Vue-Request not sending Authorization Header

I'm using VueJS with vue-request for http requests. I'm trying to subscribe an user to a Mailchimp list but Mailchimp uses BasicAuth, so I'm doing as such:
scope.$http.post('https://us15.api.mailchimp.com/3.0/lists/listid/members',
{...mydata...}, {headers: {Authorization: 'Basic myencodedAPIkey'}})
But I get an error from the API: 401 Unauthorized - Your request did not include an API key.
So I check the Network log on Chrome and the Authorization is on my headers like this: **Access-Control-Request-Headers: authorization** but it should be like **Authorization: myencodedAPIkey**
On the Console the error appears as:
XMLHttpRequest cannot load
https://us15.api.mailchimp.com/3.0/lists/listid/members. Response
to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://127.0.0.1:8000' is therefore not allowed
access. The response had HTTP status code 401.
When I use Postman it works just fine as the header is correctly sent.
This problem seems to have been solved here with setting the header on every request
https://laracasts.com/discuss/channels/vue/how-to-solve-the-allow-control-allow-cross-in-the-vuejs-header-request-setting?page=2
and here through setting it once
Vue-Request not sending Authorization Header
You are getting CORS error, when you are trying to request from one host to another, and the 'another' part does not allow it to happen. To prevent this error you can use webpack proxy configuration, so this way you do not have cross origin request, but I don't know how you will deal with this in production environment if your api does not allow cross origin requests.
In a project I'm working on, our devServer configuration is as follow
proxy: {
'/api': {
target: 'http://localhost:8080/'
}
},
with this, any request happening on /api/any/url will be redirect to localhost:8080/api/any/url

Resources