I am new to nodejs + Express but I'm trying to build a very quick proof of concept website which allows user to authenticate via a REST API.
I have come against a CORS problem and despite installing the cors module and using it as suggested in the documentation, I am still getting the following error:
Access to XMLHttpRequest at xxx has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: The
'Access-Control-Allow-Origin' header has a value
'https://www.example.com' that is not equal to the supplied origin.
Here is my (simplified) code:
app.js
const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const cors = require('cors');
compression = require('compression'),
shouldCompress = (req, res) => {
if (req.headers['x-no-compression']) {
// don't compress responses if this request header is present
return false;
}
// fallback to standard compression
return compression.filter(req, res);
};
const app = express();
// EJS
app.use(expressLayouts);
app.set('view engine', 'ejs');
// Parsing related
app.use(express.urlencoded( { extended: false })); //Parse URL-encoded bodies
app.use(express.json()); //Used to parse JSON bodies
app.use(compression({
filter:shouldCompress,
threshold: 3
}));
app.use(express.static('public'));
app.disable('x-powered-by');
// Using the flash middleware provided by connect-flash to store messages in session
// and displaying in templates
const flash = require('connect-flash');
app.use(flash());
// Sessions
const session = require('express-session');
app.use(session({
secret: 'fat cat 42',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
// Initialize Passport and restore authentication state, if any, from the session.
const passport = require('passport');
require ('./config/passport')(passport);
app.use(passport.initialize());
app.use(passport.session())
// Routes
app.use('/', require('./routes/index'));
app.use('/member', require('./routes/users'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server started on port: ${PORT}`));
users.js
const express = require('express');
const router = express.Router();
const passport = require('passport');
require ('../config/passport')(passport);
router.post('/signin', passport.authenticate('facebook', {
successRedirect : '/home',
failureRedirect : '/'
}));
module.exports = router;
Here is the script portion of the view that makes the AJAX POST
homepage.ejs
$(document).ready(function(){
$('#demo').click(function(e){
$.ajax({
method: "POST",
url: "/member/signin",
data: {
"source": $(this).attr('id')
},
dataType: "json",
timeout: 5000 // 5000ms
}).done(function(data) {
// is called if request is successful
console.log('Success:' + data);
}).fail(function(jqXHR, status) {
// is called if request fails or timeout is reached
alert('Request could not complete: ' + status);
});
});
});
How do I fix this so that the AJAX calls work?
essentially you need to permit cross-site origin requests. you do that by setting the access-control-headers normally with some proxy like nginx in front of your node server like the following (it is not recommended to have node directly exposed on port 80)
#nginx config
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, HEAD, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With';
return 204;
}
if you have expressjs you could use this cors middleware
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.post('/signin/', function (req, res, next) {
// ....
})
Related
Req.cookies is undefined whilst req.headers.cookie contains the cookies, I am using cookie-session and express. I am declaring cookie-session before the routes. For refrence I grabbed my code from this article: https://medium.com/#manishsharma8301/google-oauth-using-passport-js-how-to-get-started-46a200c1fec3
Only difference is that I am using spotify oauth instead.
app.use(
cors({
origin: "http://localhost:8888",
methods: "GET, HEAD, PUT, PATCH, POST, DELETE",
credentials: true
})
)
app.use(bodyParser.json());
app.use(cookieSession({
name: 'session-name',
keys: ['key1', 'key2']
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', authRoutes);
app.listen(8888, () => console.log(`App listening on port ${8888}`));
As per doc:
Create a new cookie session middleware with the provided options. This middleware will attach the property session to req, which provides an object representing the loaded session. This session is either a new session if no valid session was provided in the request, or a loaded session from the request.
So see if the cookie is attached to the req.session not req.cookie.
Reference :
https://www.npmjs.com/package/cookie-session#:~:text=Create%20a%20new,from%20the%20request.
An example which i got working with your code was
var cookieSession = require('cookie-session');
var express = require('express');
var cors = require('cors');
const passport = require('passport');
var app = express();
app.use(
cors({
origin: 'http://localhost:1000',
methods: 'GET, HEAD, PUT, PATCH, POST, DELETE',
credentials: true,
})
);
app.use(
cookieSession({
name: 'sessiontwo',
keys: ['key1', 'key2'],
})
);
app.use(passport.initialize());
app.use(passport.session());
app.get('/', function (req, res, next) {
console.log('Session', req.session);
// Update views
req.session.views = (req.session.views || 0) + 1;
// Write response
res.end(req.session.views + ' views');
});
app.listen(1000, () => console.log(`App listening on port ${1000}`));
// Result of get('/') 1 view and increments on reload
I'm new to node and am having some probably very basic trouble with an error message that I cannot fix:
proj/node_modules/express/lib/application.js:210
throw new TypeError('app.use() requires a middleware function')
I've been trying to use the csrf token module but for some reason I'm getting the above error code - literally clueless as to finding a fix here. May be very obvious to some - does anyone have any ideas?
This is the offending line of code: app.use(csrfProtection); // ERROR HERE: REASON UNKNOWN
I have installed the csurf module exactly identically to the tutorial I'm following. Any help would be much appreciated - original code is below:
const express = require('express');
const path = require('path');
const app = express();
const bodyParser = require('body-parser'); // enables use of body parser - body parser helps get data entered from a form (via req.body)
const subRoutes = require('./routes/subs');
const adminRoutes = require('./routes/admin');
const authRoutes = require('./routes/auth');
const mongoConnect = require('./util/database').mongoConnect;
let mailActivator = require('./util/nodemailer'); // activates nodemailer.js
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session); // session argument from express-session
const csrf = require('csrf');
const store = new MongoDBStore({
uri: 'mongodb+srv://_____:______#empool-3klmr.mongodb.net/______',
collection: 'sessions'
});
const csrfProtection = csrf();
app.set('view engine', 'ejs'); // use EJS templating engine
app.set('views', 'views'); // views located here
app.use(bodyParser.urlencoded({
extended: false
})); // parses text as URL encoded data (which is how browsers tend to send form data from regular forms set to POST) and exposes the resulting object (containing the keys and values) on req.body)
app.use(bodyParser.json()); // for JSON post API requests
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: "my secret",
resave: false,
saveUninitialized: false,
store: store
}));
app.use((req, res, next) => {
console.log('This demo middleware will always run...');
console.log('req.get("host")', req.get("host"));
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
app.use((req, res, next) => {
res.locals.isLoggedIn = req.session.isLoggedIn;
res.locals.csrfToken = req.csrfToken();
next();
});
app.use(csrfProtection); // ERROR HERE: REASON UNKNOWN
app.use(subRoutes);
app.use(authRoutes);
app.use(adminRoutes);
//app.listen(3000);
mongoConnect(() => {
app.listen(process.env.PORT || 3000);
});
console.log('App running successfully...');
Here
I know there are a lot of answer already marked as a working solution, but I can't make it work in my case, so please don't marked it as already answered, this is my scenario:
AJAX CLIENT SIDE
var data ={};
data.test="ciaozio";
$.ajax({
url: 'http://localhost:5000/dir',
method: "POST",
contentType: "application/json",
data: JSON.stringify(data),
header: "Access-Control-Allow-Origin",
success: function(data){
console.log(data);
},
error: function(data) {
console.log("error");
}
});
NODEJS SERVER-SIDE
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var router = express.Router();
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
app.use(bodyParser.json()); // support json encoded bodies
app.use('/', router);
app.post('/dir', function (req, res) {
console.log(req.body);
res.end("Ok");
})
var server = app.listen(5000, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
CONSOLE-OUTPUT
Example app listening at http://:::5000
{}
CLIENT-SIDE CONSOLE OUTPUT
Access to XMLHttpRequest at 'http://localhost:5000/dir' from origin 'null' 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.
index.js:29 error
jquery-3.4.1.min.js:2 POST http://localhost:5000/dir net::ERR_FAILED
You need to add and configure CORS to your request.
Steps:
1.Install cors npm package
npm install cors
2.Node server-side snippt
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
//app.use(...) lines;
// app.post(..) lines;
I have a Web Application using NodeJS + AngularJS, I want to integrate OKTA SAML with my application(Using Okta as IdP, using our Application as SP), right now I have some info after configuration on Okta End, it like this:
https://www.pastepic.xyz/image/image.abqL4
https://www.pastepic.xyz/image/image.ab3G3
I have Idp Single-Sign On URL, IdP Issuer, X.509 Certificate and also MetaData.
My question is how to integrate it with NodeJS oR AngularJS, How should I use the data from okta.
I have tried to use passport library in NodeJS, the app.js like this:
var express = require("express");
var path = require("path");
var bodyParser = require("body-parser");
var routes = require("./api/routes");
var http = require("http");
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var passport = require('passport');
require("./api/helper/global_function");
// Defining the port and env to run on
const { environment, port, samlUrl } = require('./appconfig.js');
const PORT = port || 8000;
const ENV = environment || 'dev'
const SAMLURL = samlUrl
const config = require('./api/auth/config.js')[ENV];
require('./api/auth/passport.js')(passport, config);
var app = express();
app.set("port", PORT);
app.set("env", ENV)
app.set("samlUrl", SAMLURL)
// To Allow CORS calls
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', true);
return next();
});
app.use(morgan('combined'));
app.use(cookieParser());
app.use(session(
{
resave: true,
saveUninitialized: true,
secret: 'something'
}));
// Enable parsing of posted forms
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use(passport.session());
// Set static directory before defining routes
app.use(express.static(path.join(__dirname, "dist")));
app.use("/node_modules", express.static(__dirname + "/node_modules"));
// Add some routing
app.use("/", function (req, res, next) {
if (req.isAuthenticated()) {
console.log(req.isAuthenticated())
return next();
}
req.session.returnTo = req.originalUrl;
res.redirect(samlUrl);
});
app.use("/api", routes);
app.use("*", (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
// To verify the listen is up and running
var server = app.listen(app.get("port"), function () {
var port = server.address().port;
console.log("Magic happens on port " + port);
});
It doesn't work because all request is unauthenticated, when I make a api call, the application keep directing me to single sign on page.
Maybe I am absolutely wrong about this, can somebody help me out? Give me a hint or tell me some basic logic
Can any people help with SAML? If any unclear, please add a comment or answer, I will check in a very short time.
I'm running an issue with my Angular 2 web app.
On Node JS server side, I got an issue with CORS preflighting.
I want to upload a file on the server, and when I do it, I have this issue :
XMLHttpRequest cannot load http://localhost:4000/upload. Response to preflight request doesn't pass access control check: 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.
where localhost:4000 is my server and localhost:3000 is my client.
My server.js file is like this :
require('rootpath')();
var express = require('express');
var app = express();
var cors = require('cors');
var bodyParser = require('body-parser');
var expressJwt = require('express-jwt');
var config = require('config.json');
var multer = require('multer');
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// // use JWT auth to secure the api
app.use(expressJwt({ secret: config.secret }).unless({ path: ['/users/authenticate', '/users/register'] }));
// // routes
app.use('/users', require('./controllers/users.controller'));
app.use('/challenges', require('./controllers/challenges.controller'));
// NEW UPLOAD
app.use(function(req, res, next) { //allow cross origin requests
res.setHeader("Access-Control-Allow-Methods", "POST, PUT, OPTIONS, DELETE, GET");
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Credentials", true);
next();
});
/** Serving from the same express Server
No cors required */
app.use(express.static('../client'));
app.use(bodyParser.json());
var storage = multer.diskStorage({ //multers disk storage settings
destination: function (req, file, cb) {
cb(null, './uploads/');
},
filename: function (req, file, cb) {
var datetimestamp = Date.now();
cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1]);
}
});
var upload = multer({ //multer settings
storage: storage
}).single('file');
/** API path that will upload the files */
app.post('/upload', function(req, res) {
upload(req,res,function(err){
console.log(req.file);
if(err){
res.json({error_code:1,err_desc:err});
return;
}
res.json({error_code:0,err_desc:null});
});
});
// FIN NEW UPLOAD
// start server
var port = process.env.NODE_ENV === 'production' ? 80 : 4000;
var server = app.listen(port, function () {
console.log('Server listening on port ' + port);
});
The weirdest thing is that, when I remove the following part, the upload is working :
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// // use JWT auth to secure the api
app.use(expressJwt({ secret: config.secret }).unless({ path: ['/users/authenticate', '/users/register'] }));
// // routes
app.use('/users', require('./controllers/users.controller'));
app.use('/challenges', require('./controllers/challenges.controller'));
But then, I got other issues :
(I did not include http prefix before localhost due to reputation)
1) zone.js:2019 OPTIONS localhost:4000/users 404 (Not Found)
2) XMLHttpRequest cannot load localhost:4000/users. Response for preflight has invalid HTTP status code 404
3) EXCEPTION: Response with status: 0 for URL: null
4) Uncaught Response {_body: ProgressEvent, status: 0, ok: false, statusText: "", headers: Headers…}
I think we have to fix the cors() part in the first example but I don't know what to really do.
Thanks
UPDATE : After modifying with your code, I'm running a new issue :
XMLHttpRequest cannot load localhost:4000/users. Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response
and when I try to upload my file, I got a new issue :
POST localhost:4000/upload 401 (Unauthorized)
I tried to add many origins in an array instead of only localhost:3000, but nothing changes.
Anything else : if I add "Origin","Content-Type","Accept" to the list of headers, I have this following error :
OPTIONS localhost:4000/users net::ERR_CONNECTION_REFUSED.
I got to admit CORS is a bit difficult.
According to the cors docs, https://github.com/expressjs/cors, to enable CORS Pre-Flight you should add the following code:
app.options('*', cors()) // include before other routes
You can also enable it for specific routes:
app.options('/products/:id', cors()) // enable pre-flight request for DELETE request
app.del('/products/:id', cors(), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})