CORS issue in API gateway lamba-proxy integration - node.js

I'm currently on a serverless application and my serverless.yml looks like
functions:
app:
handler: server.run
events:
- http:
path: /api/{any+}
method: ANY
- http:
path: /secure/api/{any+}
method: ANY
cors :
origins
- domain-url-1
- domain-url-2
As you can see above one is a secured route and that requires authorization whereas the non-secure route doesn't require any authorization headers to be passed. Since lambda-proxy doesn't take api gateway response I'm attaching the response headers on my app.js as below and for every route I'm sending the status and status codes separately in res objects.
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Request-Headers", "*");
// res.headersSent("Access-Control-Allow-Headers", "Content-Type");
res.header('Access-Control-Allow-Headers', "Origin, X-Requested-With, Content-Type, Accept, Authorization, accesstoken");
res.header('Access-Control-Allow-Credentials', true);
next();
});
But my api gateway works fine for non-secure routes while for secure routes I'm getting a CORS issue with
** Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
polyfills.ff5fcb5319b1dc651f7b.js:1 GET https://8nv8r4ph65.execute-api.us-east-1.amazonaws.com/staging/secure/api/v1/legal/notification/list?rowsPerPage=15 net::ERR_FAILED **
I'm not sure where I'm going wrong.

Your origin header does not match specified domains in ApiGateway. For fast verification remove specified domains in serverless.

This is because your secured routes are using one of the methods to pass authentication status that the browser detects as being a request with credentials. Some of the ways a browser marks a request as credentialed is if the request sends back a cookie or if the request includes the Authorization header.
Credentialed requests have an additional rule regarding CORS. The origin * is illegal for credentialed requests. Browser manufacturers instead want server admin/backend developers to tell the browser exactly what domain name is valid for the CORS request.
In addition to the rule above, list of domain names are also illegal for credentialed requests. A request with credentials can only accept one domain for CORS.
You can of course hardcode the domain name of your frontend in your server code. But this gets annoying and is not flexible in case you need to serve multiple domains.
The correct working solution for this scenario (indeed, the way CORS was intended to be used) is to check the Origin header in the request.
The laziest way to make it work is to simply copy the Origin header to Access-Control-Allow-Origin:
res.header("Access-Control-Allow-Origin", req.get("Origin"));
This will allow anyone in the world from any website to access your data. This is perfectly fine if you are OK with this and only care about using authentication to protect your data instead of also using the CORS mechanism.
If you are using the cors middleware you it will do this for you if you pass true as origin:
app.use(cors({ origin: true }));
The way CORS is intended to be used is to check the Origin against a list of approved domains:
const approvedDomains = [
"https://www.google.com",
"https://my.application.com",
"http://my.application.com" // etc..
]
function checkDomains(origin) {
return approvedDomains.filter(domain => domain === origin)[0];
}
res.header("Access-Control-Allow-Origin", checkDomains(req.get("Origin")));
Again, the cors middleware makes this simple allowing you to pass an array of approved domain names and it will do the above logic for you:
app.use(cors({ origin: approvedDomains });

Related

Azure Functions: sudden CORS issue (after hours of copacetic development)

Getting this error "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource ..."
But I had been developing from my localhost:* just hours before. I did nothing to the application settings or CORS settings. Now I have a wildcard and it still doesn't work (above error).
I checked out {app}.scm.azurewebsites.net/Env.cshtml and I see:
...
APPSETTING_WEBSITE_CORS_SUPPORT_CREDENTIALS = True
...
WEBSITE_CORS_SUPPORT_CREDENTIALS=False
...
I don't know if these environment variables are correct or if they changed since my functions were actually working.
While I've found a solution, it probably makes sense to address this problem anyhow.
const proxy = require('express-http-proxy');
const app = require('express')();
const subdomain = '';
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:1234');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.use('/', proxy(`https://${subdomain}.azurewebsites.net`));
app.listen('9091', () => {
console.log('Proxy on http://localhost:9091')
})
Then just pass in proxyUrl as a parameter if you want to preconfigure HATEOAS links.
I think that Azure App Service CORS is taking precedence over your application CORS settings. Quoting from another reply "If you enable one origin domain in App Service, and enable all domains in your Web API code your Azure API app will only accept calls from the domain you specified in Azure".
Here is the link to the other thread: Enable Access-Control-Allow-Credentials header in Azure website (Azure App Services)
I hope that you find this answer helpful :)

Express: does cors configuration depend on server TTL?

I've successfully deployed my Express API app to AWS elastic beanstalk. I have a React front end that is hosted on S3.
Both are on the same domain with the front end being at example.com & the API at api.example.com
Both have certificates and are secured.
const express = require('express');
const cors = require('cors')({
Origin: 'https://example.com'
});
// followed by required middleware
app.use(cors());
//followed by app constants
app.use((e, req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://example.com");
res.header('Access-Control-Allow-Methods', 'DELETE, PUT, GET, POST');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if (e) {
console.log(e);
res.status(500).send(e.message);
}
next();
})
// followed by app routes
When I try and register a user on my site, I get the error:
Access to XMLHttpRequest at 'https://api.example.com/users/signup/' from origin 'https://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This topic has of course been covered multiple times on Stack Overflow (which I've gone through multiple solutions this morning), but my question has to do with the actual server where the API is being hosted.
In the hosted zone for api.example.com, it has a TTL of 172800(48 hours). Does this mean that my changes won't be reflected in that time? If that is the case, does this mean that every time you deploy code it resets the TTL?
I'm a front end dev working on a side project, so this really isn't my area of expertise. Any DevOps or BackEnd Devs have any ideas? Thanks in advance!
In the hosted zone for api.example.com, it has a TTL of 172800(48 hours). Does this mean that my changes won't be reflected in that time? If that is the case, does this mean that every time you deploy code it resets the TTL?
No.
The TTL is how long other DNS servers are expected to cache the DNS information (e.g. which server the domain name points to).
It has nothing to do with deployment of code.
Your problem is unrelated to that. I'd add some logging to the server-side code to see which routes and middleware were actually hit as well as monitoring the precise request and response you are getting in the Network tab of your browser.
There a preflight OPTIONS request can be made by the browser for the particular types of cross-domain requests. If the response on that request is not successful or doesn't have CORS headers you will also get such error.
So I suppose that you should add a route in your Express app to handle preflight requests and send back the same CORS headers or just use express-cors-middleware.

Can't get past CORS error on secured Google Cloud Function

I have a Google Cloud Function. I created credentials for my project and authorized http://localhost & http://localhost:3000 as origins. I also have a Google user account that I gave the cloudfunctions.functions.invoke role to. I confirm this by going to the cloud function in the console and expand the "Cloud Functions Invoker" item and see my account listed there.
I can successfully access the function with curl.
curl https://[google-cloud-server]/test5 -H "Authorization: bearer my-identity-token"
However, if I try to invoke the function from my React app (I tried both axios and fetch), I get the following error....
Access to XMLHttpRequest at 'https://[google-cloud-server]/test5?a=b' 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.
A couple things to note...
There are no CORS problems if I make the function accessible to allUsers
Through logging, I have confirmed that, when secured, the request never makes it to the function where I have my CORS code for checking pre-flight OPTIONS. This makes sense as it is supposed to be secured by Google. But all documentation I find on Google Cloud functions talking about handling CORS-related stuff from within the function. Something is responding to my React app's request before it reaches my function. I have no idea what/where.
I added so many tags to this post because I really don't know which layer is causing the problem. I'm probably doing something really obvious/stupid, but I'm out of ideas!
Cloud function....
exports.test5 = (req, res) => {
console.log('function invoked');
// Set CORS headers for preflight requests
// Allows GETs from any origin with the Content-Type header
// and caches preflight response for 3600s
res.set('Access-Control-Allow-Origin', '*');
if (req.method === 'OPTIONS') {
console.log('Determined it is OPTIONS request');
// Send response to OPTIONS requests
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Authorization');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
} else {
console.log('Main function body');
res.send('Hello World!');
}
};
Call from React client...
const config =
{
params: payload,
headers:
{
Authorization: `bearer ${window.IDENTITY_TOKEN}`
}
};
axios.get(url, config)
.then((res) => {
...
})
.catch((err) => {
handleError(err);
});
Any ideas?
Thanks
CORS preflight OPTION request does not have an Authorization header and Cloud functions IAM prevalidates the Authorization header and will not call the function if it is missing.Therefore in order to serve the CORS preflight response you have to allow allUsers access to your cloud function.
Edit
They updated the documentation
If you want to build a web app that is secured with Google Sign-in and
Cloud Functions IAM, you'll likely have to deal with Cross-Origin
Resource Sharing (CORS). CORS preflight requests are sent without an
Authorization header, so they will be rejected on all non-public HTTP
Functions. Because the preflight requests fail, the main request will
also fail.
To work around this, you can host your web app and function(s) on the
same domain to avoid CORS preflight requests. Otherwise, you should
make your functions public and handle CORS and authentication in the
function code.
Alternatively, you can deploy a Cloud Endpoints proxy and enable CORS.
If you want authentication capabilities, you can also enable Google ID
token validation, which will validate these same authentication
tokens.

How do I properly make api calls in deployment using create-react-app with an expressjs backend?

I am trying to deploy a react application to the server.
When my deployed app tries to make calls to an api on the same server it receives the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3045/login. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘http://xxx.xxx.x.xx:5000’).
The package.json file has the proxy specified:
"proxy": "http://localhost:3045",
And here is my api call:
fetch('/login',
{
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
password
})
})).json()
What confused me further, when I had the site being served from the remote server, accessed it from my own local machine, and had the backend being served on my local machine, the site was making calls to my own local port(successfully, once I noticed what was going on and changed the cors config origin to the remote server's ip to test), and accessed the api being served from my local machine, instead of on it's (the remote deployment server's) own local port.
My cors config on the remote server api:
app.use(
cors({
origin: 'http://localhost:5000',
credentials: true,
}),
What changes do I need to make so that my site is making api calls to its own local ports, instead of the clients?
From memory (and running into a similar issue) proxying isn't mean to work when you deploy.
See Create-React-App Proxy in Production Build
Try setting it up without any special cors module:
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5000');//If it doesn't work, change it to "*"
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,token');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});

simpleWebRTC with Signalmaster - allow origion

My web app using the simpleWebRTC for video chat.
I deployed the signalmaster in Azure web app.
On localhost - the video chat working well.
Once I change the "SimpleWebRTC url" to point to the real server - I got an error:
"Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials"
I defined the Azure CORS to point to specific server - for allow my origin.
What it mean "Credentials flag is 'true'" - where?
Where can I define the 'Access-Control-Allow-Credentials' header to be true?
I tried to init the server like this:
server = http.createServer(function(req,res){
// Set CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
...
Thanks

Resources