CORS - not enabling - node.js

SOLUTION:
I had my port hardcoded... smh
app.listen(5432, () => {
console.log(`Server is listening on port 5432`)
})
Heroku REQUIRES a process.env.PORT, this solved the issue here:
require("dotenv").config()
const PORT = process.env.PORT || 5432
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`)
})
PROBLEM:
I have a simple ReactJS CRUD form with no validation hosted locally, and a NodeJS Express server hosted on Heroku. Just trying to get cors enabled but nothing I do is setting the headers for the preflight request. Receiving this error:
Access to XMLHttpRequest at
'https://cors-be.herokuapp.com/api/user/create' 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.
This is the index.js:
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json())
app.options("*", cors()) // Edit 1
app.get("/", (req, res) => {
res.json({message: "API is listening"})
})
const userRouter = require("./api/user/router")
app.use("/api/user", userRouter)
app.listen(5432, () => {
console.log(`Server is listening on port 5432`)
})
CORS version installed in package.json:
"cors": "^2.8.5"
This should be enabling all cors across all origins but it isn't. I've tested it on Chrome, Firefox, and Edge with the same result so I'm sure it's not a browser-specific issue. Everything functions correctly on localhost. It's a preflight request error so it wouldn't be an issue with my endpoint code anyway. Been working on this longer than I care to admit and I'm at the point where I will be happy just to get past the preflight request and add origin configuration later.
Edit 1:
Pre-flight seems to be looking for OPTIONS so I've added:
app.options("*", cors())
new index.js:
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json())
app.options("*", cors())
but still isn't working...

Related

CORS in node blocks POSTMAN to get data?

I'm using POSTMAN dev tool to test this API :
http://localhost:3000/users
and I have this express.js script :
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const mongoConfig = require("./config/mongodb.config");
var bodyParser = require("body-parser");
// Routers
const userRouter = require("./core/user/user.route");
const app = express();
const port = process.env.PORT || 3000;
const URI = mongoConfig.mongoURI;
const connectionOptions = mongoConfig.connectionOption;
// Connect Mongo Atlas database
mongoose
.connect(URI, connectionOptions)
.then(() => {
console.log("Connection is established successfully ...");
})
.catch((err) => {
console.error(err);
});
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.json());
app.use(cors);
app.use("/users", userRouter);
app.listen(port, () => {
console.log("The server is running on port", `${port}`);
});
The problem is when I remove CORS :
// app.use(cors);
POSTMAN can get data but when I add CORS it blocks and returns this stack trace :
Could not get any response
There was an error connecting to http://localhost:3000/users.
Why this might have happened:
The server couldn't send a response:
Ensure that the backend is working properly
Self-signed SSL certificates are being blocked:
Fix this by turning off 'SSL certificate verification' in Settings > General
Proxy configured incorrectly
Ensure that proxy is configured correctly in Settings > Proxy
Request timeout:
Change request timeout in Settings > General
As far as I know, POSTMAN is dev tool and CORS is related only with a browser but I did not understand the reason behind it.
After debugging my server.js I found the bug was inside my server and it's not related to POSTMAN.
The problem is using cors before user using my routers will block the server ( unlimited looping ).
So when I changed this code :
app.use(cors);
app.use(express.json());
app.use("/users", userRouter);
To
app.use("/users", userRouter);
app.use(cors);
app.use(express.json());
The issue is solved but I did not understand why and what happens exactly inside the server.

Why do I get a CORS Error when tunneling through ngrok?

I know this kind of problem has been solved before, but I can't figure out exactly why it is not working for my case.
I am working on a website locally and I want to test it out on various platforms and devices so I decided to use ngrok for this.
My front-end is running on port 3000 and my express server on port 5000.
So I opened ngrok and entered ngrok http 3000
On my local PC, where the server is running, the https://example.ngrok.io is working as intended without any problems.
But on my laptop (or another device), the front-end displays correctly but when it is actually going to get data from the back-end, it is showing the error: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/weather/51.87575912475586,0.9436600208282471. (Reason: CORS request did not succeed).
On my express server, I made sure to use the cors package and app.use(cors()); and I also tried adding the headers manually :
app.all('/*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
Source: Why doesn't adding CORS headers to an OPTIONS route allow browsers to access my API?
Here is also my code where I am fetching and getting data in case I am doing something wrong there:
index.js (front-end)
const response = await fetch(`http://localhost:5000/weather/${lat},${lng}`); //sending request to server-side
const json = await response.json();
console.log(json); //getting the weather data from server-side
server.js (back-end)
const express = require("express");
const mongoose = require("mongoose");
const fetch = require("node-fetch");
const cors = require('cors');
const nodemailer = require('nodemailer');
require('dotenv').config();
const users = require('./routes/api/users');
const app = express();
//Json Middleware
app.use(express.json());
app.use(cors());
//Getting URI from keys file
const db = require('./config/keys').mongoURI;
//Connect to the Database
mongoose.set('useUnifiedTopology', true);
mongoose.set('useCreateIndex', true);
mongoose.connect(db, {useNewUrlParser: true})
.then(()=> console.log("Database Connected"))
.catch(err=> console.log(err));
//Route for user routes
app.use('/api/users',users);
const dbport = process.env.PORT || 5000;
app.listen(dbport, () => console.log(`Server started on port ${dbport}`));
app.get('/weather/:latlon', async (req,res) =>{ //awating request from client-side
const latlon = req.params.latlon.split(',');
console.log(req.params);
const lat = latlon[0];
const lon = latlon[1];
console.log(lat,lon);
const api_key = process.env.API_KEY;
const weather_url = `https://api.darksky.net/forecast/${api_key}/${lat},${lon}?units=auto`; //getting data from weather API
const fetch_res = await fetch(weather_url);
const json = await fetch_res.json();
res.json(json); //sending weather data back to client-side
});
Is this possible to work or not due to the nature of localhost?
Both firefox and chrome had the same problem.
Thanks for the help!
After some days of head scratching, I finally found a solution and I'm posting it below for others that may have the same problem.
Step 1:
Instead of having 2 ports active (3000 for client and 5000 for server), I closed my client port and served my client folder/assets directly from my server using express:
const dbport = process.env.PORT || 5000;
app.listen(dbport, () => console.log(`Server started on port ${dbport}`));
app.use(express.static('client')); //serving client side from express
//Json Middleware
app.use(express.json());
Step 2:
Now that we have one port (port 5000) for both the client and the server, I went into my client side where I did my fetch requests (see above at index.js) and modified the actual requests to be relative:
const response = await fetch(`/weather/${lat},${lng}`); //sending request to server-side
const json = await response.json();
console.log(json); //getting the weather data from server-side
Step 3:
Finally, I opened ngrok and typed:
ngrok http 5000
It should now work.
If you are using ngrok with nodejs/express.js .
Remove he cors import and use this code:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN.TLD"); // update to match
the domain you will make the request from
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-
Type, Accept");
next();
});
replace "YOUR-DOMAIN.TLD" with "*" to give access to all urls OR your specific website url.
Refer to https://enable-cors.org/server_expressjs.html for more details
Thank You.

Allowing CORS in NodeJS

I defined my Express js app:
const express = require('express')
var history = require('connect-history-api-fallback');
const path = require('path')
const http = require('http')
const socketio = require('socket.io')
require('./db/mongoose')
const userRouter = require('./routers/user')
const publicDirPath = path.join(__dirname, '../public')
const app = express()
app.use(express.static(publicDirPath))
app.use(history({
index: '../public/index.html'
}))
app.use(express.static(publicDirPath))
app.use(express.json())
app.use(userRouter)
const server = http.createServer(app)
const io = socketio(server)
io.on('connection', socket => {
console.log('New WebSocket connection')
socket.on('join', () => {
socket.emit('message', 'Welcome to the app')
})
})
module.exports = server
Then I use it my index.js file:
const app = require('./app')
const port = process.env.PORT
app.listen(port, () => {
console.log(`Server is up on port ${port}`)
})
When I run the app and send requests from the same port - everything works just fine. But when I try to send requests from different localhost port, ie. 8080, I'm getting cross origin error.
I tried to install cors package and use it as follows:
const cors = require('cors')
app.options('*', cors())
app.use(cors());
And got the same result.
I tried to pass configuration to cors:
app.use(cors({
origin: 'http://localhost:8080'
}));
And still got the same result.
What am I doing wrong and how can I make it work?
When your frontend app tries to make the request to the express server,
The express server is blocking that request because the source of the request (i.e. frontend server) is unknown to the express server
As the request that you are trying to make it out of the domain of the express server. this is the reason where you have to tell the server please accept the request from this origin a.k.a IP Address
and you can achieve the via cors
Let's take a minute to explain what "origin" is in simple words.
When a user browses to a website, he uses an address.
Normally that address is a domain, but when we run our tests we mostly work with local IPs.
For CORS, this doesn't matter. Once you enable Allow-Origins, the server looks at the address the user used to reach the website, and defines it as the "origin" of the request.
Obviously, on a deeper level, everything comes down to IP addresses. But when it comes to CORS, it's more of a high-level security method. It's helps preventing Cross-Site Request-Forgeries for example.
In conclusion, in order for CORS to work,
make sure you allowed the address which the user is using to access the HTTP service.
So, if you're serving a VUE app that's working on http://localhost:8080, and from it calling to an HTTP service on http://localhost:5555, you'll need to do this on the said HTTP service:
app.use(cors({
origin: 'http://localhost:8080'
}));

Angular client enable CORS

CORS is fine on server and works as intended. I tried sending requests to my server's REST API with the angular HTTPClient and I receive a CORS error.
Why is this an error if CORS is enabled on the server? Shouldn't it be fine on the client?
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3000/api/blah/blah (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
How can I enable CORS on this request please.....
For future refrence it was "Davids" answer that assisted me, the cors was not added before all routing.
"..... Meaning, before the route is defined."
so right after ...
var app = express();
I just use...
app.use(cors());
A little intro:
Cross-Origin Resource Sharing aka CORS is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin (e.g. http://localhost:3000), access to selected resources from a different origin (e.g. http://localhost:8080). In other words, a web app executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own. For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts.
The Access-Control-Allow-Origin header determines which origins are allowed to access server resources over CORS.
How to Fix CORS Issues?
You can do it yourself by creating an Express middleware. Here's the appropriate code snippet:
// Enable CORS for specific origins:
app.use((req, res, next) => {
// Allow multiple predefined origins
const allowedOrigins = ["https://deployed-app.com", "http://localhost:3000"];
const origin = req.headers.origin; // extract the origin from the header
if (allowedOrigins.indexOf(origin) > -1) { // if the origin is present in our array
res.setHeader("Access-Control-Allow-Origin", origin); // set the CORS header on the response
}
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next(); // move on to the next middleware
});
Alternatively, you can accept all requests,
but this option is only appropriate if you're in development or if your API is public :)
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
next();
});
Additionally, there's an Express CORS middleware and this is how you would use it:
npm install cors --save
Enable All CORS Requests:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
});
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`CORS-enabled server is up on ${port}`);
});
Enable CORS for a Single Route
const express = require('express');
const cors = require('cors');
const app = express();
app.get('/products/:id', cors(), (req, res, next) => {
res.json({msg: 'This is CORS-enabled for a Single Route'})
});
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`CORS-enabled server is up on ${port}`);
});
Important gotcha: When it comes to Express middleware, the order is very important. So make sure CORS is enabled before any other controller/ route/ middleware which may depend on it.
You dont need to enable cors in angular, this is a server side issue. See:
https://stackoverflow.com/a/29548846/4461537

Express CORS not working

I just started my nodejs express template buy cors is not working.
I used npm install cors --save
here is the file:
var express = require('express');
var cors = require('cors');
var app = express();
app.use(cors());
var corsOptions = {
origin: 'https://example.com/',
optionsSuccessStatus: 200
};
app.get('/', cors(corsOptions), function(req, res, next) {
res.json({ message: 'hooray! welcome to our api!' });
});
app.get('/tt', function(req, res, next) {
res.json({ message: 'hooray! welcome to our api!' });
});
var port = process.env.PORT || 3030;
app.listen(port);
console.log('Magic happens on port ' + port);
Now with the above code when I access localhost:3030/tt or / I still see the content and I shouldn't
What's wrong with this.. I just lost like 2 hours working on this.. :(
At this time I would like not to use CORS, but in near future when my app is finished, I want to allow incoming calls only from my project, since this app will be my API.
The behavior you are describing seems is what I would expect.
CORS won't help you filter out incoming calls on the server. In this case the browser's CORS check won't kick-in as it appears you are directly typing in the URL in the browser. Browser does a CORS check only when the the webpage loaded from a particular domain tries to access/submit to a URL in a different domain.
A different way to think about CORS. CORS is intended to protect the user sitting in front of the browser, and not the server-code that is being accessed.

Resources