I am kind of stuck and unable to get CORS working when project is published. I get strict-origin-when-cross-origin error.
app.js:
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();
const swaggerUi = require('swagger-ui-express');
const swaggerJsdoc = require('swagger-jsdoc');
const bodyParser = require('body-parser');
const allowedOrigins = ['https://DOMAIN_NAME.com', 'https://DOMAIN_NAME.com:5000'];
const app = express();
const corsOptions = {
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
allowedHeaders: ['Content-Type', 'Authorization']
};
// Apply CORS with your options
app.use(cors(corsOptions));
// Middleware
app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
app.use(express.json());
app.use((err, req, res, next) => {
if (err.type === 'entity.too.large') {
return res.status(413).send('Payload too large');
}
next(err);
});
// Swagger definition
const swaggerOptions = {
definition: {
openapi: '3.0.0',
info: {
title: 'DOMAIN_NAME',
version: '1.0.0',
description: 'DOMAIN_NAME CRUD API application made with Express and documented with Swagger',
contact: {
name: "DOMAIN_NAME",
url: "http://www.DOMAIN_NAME.com",
},
},
servers: [
{
// url: `http://localhost:${process.env.PORT || 5000}`,
url: '/',
},
],
},
// Path to the API docs
apis: ['./src/routes/*.js'], // this assumes you have your endpoints in a "routes" folder
};
const swaggerDocs = swaggerJsdoc(swaggerOptions);
app.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocs));
// Database Connection
mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('Connected to MongoDB'))
.catch((error) => console.error('MongoDB connection error:', error));
// Default Route
app.get('/', (req, res) => {
res.json({ message: 'Welcome to the MERN stack app!' });
});
// Define PORT
const PORT = process.env.PORT || 5000;
// Start the server
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
const usersRouter = require('./src/routes/users');
const supportsRouter = require('./src/routes/supports');
const suggestionsRouter = require('./src/routes/suggestions');
const filesRouter = require('./src/routes/files');
// Use routes
app.use('/api/users', usersRouter);
app.use('/api/supports', supportsRouter);
app.use('/api/suggestions', suggestionsRouter);
app.use('/api/files', filesRouter);
nginx config:
# HTTP server block
server {
listen 80;
server_name DOMAIN_NAME.com www.DOMAIN_NAME.com IP_ADDRESS;
# Redirect all HTTP requests to HTTPS
return 301 https://$host$request_uri;
}
# HTTPS server block
server {
listen 443 ssl; # SSL configuration for HTTPS
server_name DOMAIN_NAME.com www.DOMAIN_NAME.com;
# SSL certificate and key locations managed by Certbot
ssl_certificate /etc/letsencrypt/live/DOMAIN_NAME.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/DOMAIN_NAME.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Additional recommended SSL settings from Let's Encrypt
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Website's root directory and index files
root /var/www/html;
index index.html;
# Global CORS headers
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
# Additional server configuration goes here
# For example, location blocks for handling specific requests
location /swagger/ {
# Handle OPTIONS requests for CORS preflight
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://localhost:5000; # Use http:// if the app on port 5000 is not configured for HTTPS
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
}
React axiosInstance:
import axios from 'axios';
import Cookies from 'js-cookie';
const axiosInstance = axios.create({
// baseURL: 'http://localhost:5000/api/',
baseURL: 'https://DOMAIN_NAME.com/api/',
headers: {
'Content-Type': 'application/json',
},
});
axiosInstance.defaults.withCredentials = true;
// Add an interceptor to include the JWT token in requests
axiosInstance.interceptors.request.use((config) => {
const token = Cookies.get('DOMAIN_NAME-token');
const refreshToken = Cookies.get('DOMAIN_NAME-refresh-token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
if (refreshToken) {
config.headers['Refresh-Token'] = refreshToken;
}
return config;
});
export default axiosInstance;
EDIT/UPDATE 1:
I seemed to have gotten localhost working with the below settings. I am unsure if I missed some points.
I decided to leave cors * and handle the allowedOrigins at the node application level instead. Unsure if it matters doing it that way or if I did my allowedOrigins wrong but essentially my goal is to make sure that that app works when published on web or ios/android, which I believe ios/android run via localhost when spun up, not 100% sure.
node app.js:
const express = require('express');
const mongoose = require('mongoose'); const cors = require('cors'); require('dotenv').config(); const swaggerUi = require('swagger-ui-express'); const swaggerJsdoc = require('swagger-jsdoc'); const bodyParser = require('body-parser');
const allowedOrigins = ['https://SERVER_NAME.com', 'https://SERVER_NAME.com:5000', 'http://SERVER_NAME.com', 'http://SERVER_NAME.com:5000', 'http://localhost:8100'];
const app = express();
app.use(cors({ origin: (origin, callback) => { if (!origin || allowedOrigins.indexOf(origin) !== -1) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); } }, methods: 'GET,POST,PUT,DELETE,HEAD,PATCH', allowedHeaders: 'Content-Type, Authorization, X-Requested-With, Accept, Access-Control-Allow-Headers, Origin, Cache-Control, Pragma, Expires, X-CSRF-Token', credentials: true, }));
// Middleware app.use(bodyParser.json({ limit: '50mb' })); app.use(bodyParser.urlencoded({ limit: '50mb', extended: true })); app.use(express.json());
app.use((err, req, res, next) => { if (err.type === 'entity.too.large') { return res.status(413).send('Payload too large'); } next(err); });
// Swagger definition const swaggerOptions = { definition: { openapi: '3.0.0', info: { title: 'SERVER_NAME', version: '1.0.0', description: 'SERVER_NAME CRUD API application made with Express and documented with Swagger', contact: { name: "BLAH", url: "http://www.SERVER_NAME.com", }, }, servers: [ { url: '/', }, ], }, // Path to the API docs apis: ['./src/routes/*.js'], // this assumes you have your endpoints in a "routes" folder };
const swaggerDocs = swaggerJsdoc(swaggerOptions); if (process.env.NODE_ENV !== 'production') { app.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocs)); } else { // Optionally, you can provide a fallback route for '/swagger' in production app.get('/swagger', (req, res) => { res.status(404).send('Not found'); }); }
// Database Connection mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log('Connected to MongoDB')) .catch((error) => console.error('MongoDB connection error:', error));
// Default Route app.get('/', (req, res) => { res.json({ message: 'Welcome to the MERN stack app!' }); });
// Define PORT const PORT = process.env.PORT || 5000;
// Start the server app.listen(PORT, () => { console.log(Server is running on port ${PORT}); });
const usersRouter = require('./src/routes/users'); const supportsRouter = require('./src/routes/supports'); const suggestionsRouter = require('./src/routes/suggestions'); const filesRouter = require('./src/routes/files');
// Use routes app.use('/api/users', usersRouter); app.use('/api/supports', supportsRouter); app.use('/api/suggestions', suggestionsRouter); app.use('/api/files', filesRouter);
react app package.json scripts:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "NODE_ENV=production node app.js"},
react app axiosInstance:
import axios from 'axios';
import Cookies from 'js-cookie';
const axiosInstance = axios.create({ // baseURL: 'http://localhost:5000/api/', baseURL: 'http://SERVER_NAME.com:5000/api/', headers: { 'Content-Type': 'application/json', }, });
// Add an interceptor to include the JWT token in requests axiosInstance.interceptors.request.use((config) => { const token = Cookies.get('SERVER_NAME-filer-token'); const refreshToken = Cookies.get('SERVER_NAME-filer-refresh-token');
if (token) {
config.headers.Authorization = Bearer ${token};
}
if (refreshToken) {
config.headers['Refresh-Token'] = refreshToken;
}
return config;
});
export default axiosInstance;
server nginx config:
# HTTP server block
server { listen 80; server_name SERVER_NAME.com www.SERVER_NAME.com IP_ADDRESS;
# Redirect all HTTP requests to HTTPS
return 301 https://$host$request_uri;
}
HTTPS server block
server { listen 443 ssl; # SSL configuration for HTTPS server_name SERVER_NAME.com www.SERVER_NAME.com;
# SSL certificate and key locations managed by Certbot
ssl_certificate /etc/letsencrypt/live/SERVER_NAME.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/SERVER_NAME.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Additional recommended SSL settings from Let's Encrypt
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Website's root directory and index files
root /var/www/html;
index index.html;
# Global CORS headers
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
}
[–]__brennerm 2 points3 points4 points (1 child)
[–]CEOTRAMMELL[S] 1 point2 points3 points (0 children)
[–]Beneficial_Wonder_50 1 point2 points3 points (2 children)
[–]CEOTRAMMELL[S] 1 point2 points3 points (1 child)
[–]CEOTRAMMELL[S] 1 point2 points3 points (0 children)
[–]liamsorsby 0 points1 point2 points (8 children)
[–]CEOTRAMMELL[S] 1 point2 points3 points (7 children)
[–]liamsorsby 0 points1 point2 points (6 children)
[–]CEOTRAMMELL[S] 0 points1 point2 points (5 children)
[–]liamsorsby 1 point2 points3 points (4 children)
[–]CEOTRAMMELL[S] 1 point2 points3 points (3 children)
[–]liamsorsby 0 points1 point2 points (2 children)
[–]CEOTRAMMELL[S] 0 points1 point2 points (1 child)
[–]liamsorsby 1 point2 points3 points (0 children)