CORS origin undefined with simple nodejs server - node.js

I have a very simple nodejs server, but using the 'cors' package seems to not recognize the origin of the request for some reason.
Here is my nodejs server config:
const cors = require('cors');
const express = require('express');
const CORS_WHITELIST = [ 'http://localhost:5000' ];
const corsOptions = {
origin: (origin, callback) => {
console.log(origin) // ----> this is always 'undefined'
if (CORS_WHITELIST.indexOf(origin) !== -1){
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
};
const configureServer = app => {
app.use(cors(corsOptions));
};
module.exports = configureServer;
Here is my server starter file:
const express = require('express');
const SERVER_CONFIGS = require('./constants/server');
const configureServer = require('./server');
const configureRoutes = require('./routes');
const app = express();
configureServer(app);
configureRoutes(app);
app.listen(SERVER_CONFIGS.PORT, error => {
if (error) throw error;
console.log('Server running on port: ' + SERVER_CONFIGS.PORT);
});
I am running this server on localhost, but the origin in the cors callback is always 'undefined'. For example when I open http://localhost:5000 on the browser or do a curl call.
How can I use cors so that it doesn't block the request on localhost?

I read this issue and req.headers.origin is undefined question and also CORS and Origin header!
source:
The origin may be hidden if the user comes from an ssl encrypted website.
Also: Some browser extensions remove origin and referer from the http-request headers, and therefore the origin property will be empty.
There is a solution to solve this by adding a middleware:
app.use(function (req, res, next) {
req.headers.origin = req.headers.origin || req.headers.host;
next();
});
I hope these helps. The issue is in awaiting more info state!

Related

How can I communicate with Cloudfront and the ec2 node server?

using stack
Client: React, Redux, axios
Server: AWS-EC2, Route 53, S3, CloudFront, NodeJS, express
First, I bought a domain from route53.(ACM certificate issuance completed)
Second, I registered the build file in the bucket as a static website in S3.
Third, linked the Route 53 and S3 bucket to CloudFront.
Fourth, EC2 set ELB and EIP.
Fifth, ec2 contains node.js epxress server.
Sixth, CloudFront, Redirect from S3 (www.domain.link => domain.link)
was set to
The code of the problematic Client and Server is as follows.
Client.js
import axios from "axios";
import { TYPES, MAF } from "./types";
const API_AUTH = "https://www.domain.link/auth";
const API_USER = "https://www.domain.link";
//필수!!
axios.defaults.withCredentials = true;
export function loggedIn(data) {
return (dispatch) => {
axios.post(`${API_AUTH}/login`, data).then((res) => {
console.log(res);
dispatch({
type: TYPES.LOGIN_SUCCESS,
// payload: res.data.userData,
});
dispatch({
type: MAF.HIDE_MODAL,
});
});
};
}
export function register(data) {
return (dispatch) => {
axios.post(`${API_AUTH}/register`, data).then((res) => {
dispatch({
type: TYPES.REGISTER_SUCCESS,
payload: res.data,
});
});
};
}
server.js
./routes/user.js
const router = require("express").Router();
const {
login,
register,
logout,
profile,
} = require("../controller/userController/userController");
const { authorization } = require("../config/JWTConfig");
router.post("/auth/login", login);
router.post("/auth/register", register);
router.get("/auth/logout", authorization, logout);
router.get("/auth/profile", authorization, profile);
module.exports = router;
./app.js
const express = require("express");
// const passportConfig = require("./passport/index");
const passport = require("passport");
const http = require("http");
const https = require("https");
const path = require("path");
const fs = require("fs");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const logger = require("morgan");
require("dotenv").config();
const authRoute = require("./routes/users");
const mainRoute = require("./routes/main");
const port = process.env.PORT || 3000;
const app = express();
const whitelist = [
"http://localhost:3000",
"http://*.doamin.link",
"http://doamin.link",
"http://doamin.link/*",
];
const corsOption = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
credentials: true,
methods: ["GET", "POST", "PUT", "DELETE", "OPTION"],
};
app.use(cookieParser());
app.use(logger("dev"));
app.use(cors(corsOption));
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.use(mainRoute);
app.use(authRoute);
let server;
if (fs.existsSync("./cert/key.pem") && fs.existsSync("./cert/cert.pem")) {
const privateKey = fs.readFileSync(__dirname + "/cert/key.pem", "utf8");
const certificate = fs.readFileSync(__dirname + "/cert/cert.pem", "utf8");
const credentials = { key: privateKey, cert: certificate };
server = https.createServer(credentials, app);
server.listen(port, () => console.log("https server Running"));
} else {
server = app.listen(port, () => {
console.log(`http server Running`);
});
}
module.exports = server;
When I click the Postman or browser login button, this error occurs.
Access to XMLHttpRequest at 'https://www.domain.link/login'
from origin 'https://domain.link' 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.
createError.js:16 Uncaught (in promise) Error: Network Error
at e.exports (createError.js:16)
at XMLHttpRequest.p.onerror (xhr.js:84)
domain.link or www.domain.link or the above error occurs.
Postman
How do I get CloudFront + S3 to communicate with EC2?
in your browser or postman
www.domain.link
After connecting to domain.link
When you make a login button or post request
I hope it works well.
If something is missing, please let me know what is missing. I will add more.
You specify allowed methods for CloudFront in your cache behavior. By default only GET and HEAD are allowed:

Can't connect to Heroku Postgres with ssl

I'm hosting a node.js backend and Postgres database on Heroku. After Heroku started requiring ssl, any requests to the database stopped working. I followed the documented fix here but I'm still getting errors. The request just hangs and eventually errors out as a CORS error.
"Access to XMLHttpRequest at [...] from origin [...] has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
Database requests work locally both in browser and Insomnia. I also tried making new Heroku projects but still run into the same error when making database requests.
Here is my db.js:
const { Client } = require("pg");
const client = new Client({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
}
});
client.connect();
module.exports = client;
app.js:
const express = require("express");
const cors = require("cors");
const app = express();
app.use(cors());
app.use(express.json());
// add logging system
const morgan = require("morgan");
app.use(morgan("tiny"));
const villagersRoutes = require("./routes/villagers");
const wakeRoutes = require("./routes/wake");
app.use("/villagers", villagersRoutes);
app.use("/", wakeRoutes);
/** 404 Not Found handler. */
app.use(function (req, res, next) {
const err = new Error("Not Found");
err.status = 404;
next(err);
});
/** Generic error handler. */
app.use(function (err, req, res, next) {
if (err.stack) console.error(err.stack);
res.status(err.status || 500).json({
message: err.message,
});
});
module.exports = app;
server.js:
const app = require("./app");
app.listen(process.env.PORT || 5000, function () {
console.log("Server is listening on port 5000");
});

Heroku backend Node.js and Netlify frontend react app has been blocked by CORS policy:

Heroku backend Node.js and Netlify frontend react app has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I've seen a lot of posts on this, but I just can't seem to fix what's creating this error. Of course, I believe it has to do with CORS. But as you can see, I've added multiple versions of CORS middleware to allow this to work. Locally everything is fine. Production/live is where I get the issue:
Access to XMLHttpRequest at 'https://seb-youtube-api.herokuapp.com//videos?page=1&limit=50' from origin 'https://seb-youtube-api.netlify.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here is my backend server with Node.js and Express.js
They make a simple call to a youtube API.
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser')
const app = express();
const cors = require('cors')
const chalk = require('chalk');
const { google } = require('googleapis');
const youtube = google.youtube('v3'); // initialize the Youtube API library
// Middleware
app.use(cors());
app.use(bodyParser.json());
/******************** GET REQUEST TO VIDEOS *********************/
app.get('/videos', async (req, res) => {
const results = await fetchYoutubePlaylist();
res.json(results)
})
// /******************** POST REQUEST, USER SEARCH *********************/
app.post('/videos', async (req, res) => {
console.log('POST QUERY',req.body)
const query = req.body
res.body = await fetchYoutubeSearch(query)
console.log("RES POST", res.body)
res.json(res.body)
})
app.use('*', cors(), (req, res) => {
return res.status(404).json({ message: 'Not Found' });
});
// CORS
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,multipart/form-data,Authorization');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE');
if (req.method === 'OPTIONS') {
return res.send(204);
}
next();
});
/******************** FIRST YOUTUBE API CALL *********************/
const fetchYoutubePlaylist = async () => {
try {
const {data} = await youtube.playlistItems.list({
key: process.env.YOUTUBE_API_TOKEN,
part: ['snippet'],
maxResults: 50,
playlistId: "UUBh8XcZST_JTHt-IZDxT_pQ"
})
console.log(data)
return data.items
} catch(err) {
console.log(chalk.red(err))
}
}
/******************** SECOND YOUTUBE API CALL *********************/
const fetchYoutubeSearch = async ({query}) => {
console.log(query)
try {
const {data} = await youtube.search.list({
key: process.env.YOUTUBE_API_TOKEN,
part: ['snippet'],
q: query,
channelId: 'UCBh8XcZST_JTHt-IZDxT_pQ',
order: 'date',
type: 'video',
maxResults: 50
})
console.log('YOUTUBE SEARCH', data)
return data.items
} catch(err) {
console.log(chalk.red(err))
}
}
/******************** LIST TO PORT *********************/
const port = process.env.PORT || 3001;
app.listen(port, () => console.log(`Listing on port ${port}`));
Is the issue that your browser is blocking CORS? That happens to me with Heroku stuff sometimes. There are browser extensions to block/unblock CORS depending on the browser you're using
Stick only with app.use(cors()); that alone should work fine. Instead double check your Config Vars (env vars) on heroku and/or netlify wherever you set such variables. Sometimes that CORS error can be misleading being actually a connection error more about your environment variables.

Getting a cors error running vue with express

I'm running my Vue App on my express server (nodejs running on port 60702) like:
'use strict';
const fs = require('fs');
const path = require('path');
const express = require('express');
var https = require('https');
const morgan = require('morgan');
const cors = require('cors');
const bodyParser = require('body-parser');
const nconf = require('./config');
const pkg = require('./package.json');
const swaggerSpec = require('./swagger');
const swaggerUI = require('swagger-ui-express');
const app = express();
app.options('*', cors()) // include before other routes
// create a write stream (in append mode)
var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {
flags: 'a'
});
// setup the logger
app.use(morgan('combined', {
stream: accessLogStream
}));
// Enable CORS (cross origin resource sharing)
app.use(cors());
// Set up body parser
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
// Load the Vue App
app.use(express.static(path.join(__dirname, '../../client/pvapp-client/dist')));
app.get('/api/version', (req, res) => res.status(200).send(pkg.version));
const userRouter = require('./routes/user');
const systemRouter = require('./routes/system');
const yieldRouter = require('./routes/yield');
const adjustmentRouter = require('./routes/adjustmentfactors');
app.use('/user', userRouter);
app.use('/system', systemRouter);
app.use('/yield', yieldRouter);
app.use('/adjustmentfactors', adjustmentRouter);
//Default route
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../../client/pvapp-client/dist/index.html'));
});
//const listener = app.listen(nconf.get('port'), () => console.log(`Ready on port ${listener.address().port}.`));
https.createServer({
key: fs.readFileSync('certs/apache-selfsigned.key'),
cert: fs.readFileSync('certs/apache-selfsigned.crt')
}, app)
.listen(nconf.get('port'), function() {
console.log(`App listening on port ${nconf.get('port')}! Go to https://192.168.51.47:${nconf.get('port')}/`)
});
The User router is:
router.post('/login', async (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods', 'GET,POST");
let compareUser = await db.query('SELECT * FROM app_users WHERE username=? LIMIT 1', [req.body.username]); // use db.query() to retrieve the password
if (compareUser.length < 1) // compareUser is an array with at most one item
res.sendStatus(403);
let valid = bcrypt.compareSync(req.body.password, compareUser[0].password);
if (!valid)
res.sendStatus(403);
let user = new User(compareUser[0]);
const token = jwt.sign({
user
}, nconf.get('jwtToken'), {
expiresIn: '14d'
});
Object.assign(user, {
token
});
res.json(user);
});
The vue config is:
module.exports = {
baseUrl: process.env.NODE_ENV === 'production' ? '/vue' : '/',
devServer: {
port: 60702,
https: true,
disableHostCheck: true
}
};
Axios:
const apiClient = axios.create({
baseURL: `https://192.168.51.47:60702`,
withCredentials: false, // This is the default
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
export default {
// user Endpoints
getUser(email) {
return apiClient.get(`/user/${email}`)
},
registerUser(user) {
return apiClient.post(`/user/register`, user)
},
loginUser(user) {
return apiClient.post(`/user/login`, user)
},
But even if I included cors I'm getting:
Cross-source (cross-origin) request blocked: The same source rule
prohibits reading the external resource on
https://143.93.46.35:60702/user/login. (Reason: CORS request failed).
The axios call in vue also has the correct baseUrl with the port.
I checked the POST request to the backend at /user/login with Postman and get the exprected correct request, too.
It was solved by re-creating the dist folder with
npm run build
Thanks to #Dan for his help
Don't use apiClient. Do a get with the full url, rebuild your app,
delete old dist folder, CTRL+F5 refresh once loaded. In fact, put a
"?" on the end of the url and make sure you see it in Chrome headers

Configuring CORS npm package to whitelist some URLs

I have an API here https://api-ofilms.herokuapp.com which send datas to my client https://ofilms.herokuapp.com,
I want to disable CORS for all origin URLs except :
- http://localhost:3000 (URL of the client in development),
- https://ofilms.herokuapp.com (URL of the client in production),
Because for now, you can see the message on https://api-ofilms.herokuapp.com but I don't want people to access the API,
I tried this before all routes :
const cors = require("cors");
app.use(
cors({
origin: ["http://localhost:3000", "https://ofilms.herokuapp.com"],
credentials: true
})
);
But I can still see API messages...
You can try passing in the origin with a callback, like this
Configuring CORS w/ Dynamic Origin
var express = require('express')
var cors = require('cors')
var app = express()
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
Source

Resources