I'm merging two little apps into one, that is supposed to be accessed via two subdomains. To do so I'm using the module "express-subdomain". I'm trying to use Passport so when a user logs in in the first app, he is logged in in both apps. However using req.isAuthenticated() I can indeed login in the "first" app, but then I'm not in the "second" one.
I'm searching for any solution to have a passport authentification in the first subdomain and being logged in in the second one, including keeping two disctinct apps if needed.
Assuming that passport is correctly configured for a local strategy, as well as the routers and the rest of the app. Here is what it looks like :
app.js
// <- requires etc
var passport = require('./configurePassport.js')(require('passport'));
var app = express();
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(expressSession({
secret: 'bestSecretEver',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
// and others
var firstRouter = express.Router();
firstRouter.use('/public', express.static(__dirname + '/first/public'));
firstRouter.use(favicon(__dirname + '/first/public/favicon.ico'));
// <- setting first router's GET, POST etc
app.use(subdomain('sub1', firstRouter)); // for sub1.example.com
var secondRouter = express.Router();
secondRouter.use('/public', express.static(__dirname + '/second/public'));
secondRouter.use(favicon(__dirname + '/second/public/favicon.ico'));
// <- setting second router's GET, POST etc
app.use(subdomain('sub2', secondRouter)); // for sub2.example.com
Any idea ?
Look into where you're saving your cookies for authentication purposes. Make sure you have it saved to the root domain. ie: *.example.com and not sub1.example.com
Related
const express = require("express");
const app = express();
var i = new Number;
i=0;
app.get("/", function(req, res){
i++
console.log(i);
});
app.listen(8080);
I created a very small node js project. I have a problem. when I create a variable like above, it doesn't evaluate for each user separately. that is, when a user requests a get, I want it to be 1 each time.
Sample
my problem is that when a jack user enters a site, if he doesn't log out, someone who enters the site's home page from another device enters his account with jack.
how can I do that?
The simplest answer for your question is to simply declare and increment the variable inside the function passed to app.get, but I'm going to assume that you would like a situation where, for a given user's series of requests, the number will increment.
The simplest way to do this is using a server side session, which is provided by the express-session library. Additionally, in order for this to work, you need to call res.end() in order to send the cookie associated with the server session back to the user's browser. More information on sessions generally can be found here.
Below is code to replicate the intent of what you have there, but incrementing for each request from a unique browser instance (identified by the same cookie value associated with the server session):
const express = require('express');
const session = require('express-session');
const app = express();
app.use(session({
resave: false,
saveUninitialized: true,
secret: 'secret',
cookie: {
maxAge: 60000
}
}));
app.get('/', function(req, res){
if (!req.session.value) {
req.session.value = 0;
}
req.session.value++;
console.log(req.session.value);
res.end();
});
app.listen(8080);
I have a problem in my bluemix application when the project has two or more instances.
If I keep the project with only one instance, this code works as expected and when the url '/load' is called, I receive the data saved in the '/save'. But, when I put more instances in the application, the '/load' sends nothing is most times.
Its like the session is saved in one instance of the project and when the user hits another url, the '/load' is being executed in another instance.
So, does anyone knows how to make sure that the user only use one instance or share the session value between the instances?
var express = require('express');
var session = require('express-session');
var cfenv = require('cfenv');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(session({
resave: 'false',
saveUninitialized: 'true',
secret: 'cub1ksqu4d_mysp0t'
}));
var appEnv = cfenv.getAppEnv();
app.get("/save", function (req, res) {
req.session.fullname = "John Galt";
res.send("Saved session");
});
app.get("/load", function (req, res) {
res.send(req.session.fullname);
});
app.listen(appEnv.port, '0.0.0.0', function () {
console.log("server starting on " + appEnv.url);
});
You should design your app as stateless process. This is actually one of the 12 factors (see 12 factor app).
If you want to share a state between invocations and between instances of your app, a common practice is to use a database to store that data. There are frameworks to allow caching of data/states across the instances.
Seems that each instance it have their own request manager and it's not shared and each request is balanced through all instances.
You can make the /save to take a name parameter and test to execute /save a few times with different names and then the /load to see if it returns "randomly" the different names given.
If you want to share information through multiple instances I would recommend the use of a db service on your app.
Think what I am trying to do should be relatively easy, but I am loosing the thread, and potentially the will to do this.
Setting up a node application using node and express 4. And I use passport for authentication. Followed an absolutely amazing guide by scott.io which did the trick nicely https://scotch.io/tutorials/easy-node-authentication-setup-and-local
And it works a charm. However, I want to separate my routes, because I like keeping things tidy (thats a lie, but I intend to keep the lie living).
My plan was to have four sets of routes.
api (mapped to /api, using the file ./routes/api.js)
index (mapped to /, using the file ./routes/index.js)
auth (mapped to /auth, keeps track of all authentication, callbacks as well as some activator and other bits)
Now to my issue, I need to make the passport available to app (or get api.js and indes.js to be able to call functions in passport.js) and I can't quite figure out how.
My plan was to initiate passport like so:
var passport = require('passport');
app.use(session({secret: 'Not-telling-you)',
saveUninitialized: true,
resave: true
})); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
//Configuring the passports
require('./config/passport')(passport);
That should give me passport available in app
Next to load the route modules
var auth = require('./routes/auth')(app, passport);
var users = require('./routes/users')(app,passport);
var activator = require('./routes/activator')(app,passport);
This SHOULD allow me to access them in the modules?
Map all toutes in app
app.use('/api', api);
app.use('/auth', auth);
app.use('/', index);
And then write the modules as follows (this is a super simple version of auth)
var bodyParser = require('body-parser');
var activator = require('activator');
var express = require('express');
var router = express.Router();
//Lets read the configuration files we need
var activatorCfg = require('../config/activator.js')
var cfgWebPage = require('../config/webpage.js');
//So we can read the headers easily
router.use(bodyParser.json()); // support json encoded bodies
router.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
//Activating activator, so we can actively activate the actives
activator.init({user: activatorCfg, transport: activatorCfg.smtpUrl , from: activatorCfg.fromEmail, templates: activatorCfg.templatesDir});
router.get('/login', function(req, res) {
res.render('login.ejs', { title: 'Betchanow - Social betting as it should be' , loginUrl: cfgWebPage.loginUrl, trackingID: cfgWebPage.googleTracking.trackingID, message: req.flash('loginMessage') });
});
module.exports=function(app, passport) {
router
}
My problem is that if I do that, express complains that
throw new TypeError('Router.use() requires middleware function but got a
^
TypeError: Router.use() requires middleware function but got a undefined
If I just return the router (skip wrapping it in a function) I end up with a
var search = 1 + req.url.indexOf('?');
^
TypeError: Cannot read property 'indexOf' of undefined
So is there a right, simple or preferably right and simple way of achieving this?
Think the trick would be to pass app and passport (or only passport), think is I need access to either data or functions from passport in all three, and as I was planning to play with ACL as well, wanted to add that to auth to make my life simple as well.
============== EDIT =============
So here is my issue.
If I now do a post to the authentication route (code below)
//Lets load the modules, note the missing passport
var bodyParser = require('body-parser');
var activator = require('activator');
var express = require('express');
var router = express.Router();
//Lets read the configuration files we need
var activatorCfg = require('../config/activator.js')
var cfgWebPage = require('../config/webpage.js');
//So we can read the headers easily
router.use(bodyParser.json()); // support json encoded bodies
router.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
//Activating activator, so we can actively activate the actives
activator.init({user: activatorCfg, transport: activatorCfg.smtpUrl , from: activatorCfg.fromEmail, templates: activatorCfg.templatesDir});
//Lets start with our routes
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
module.exports=function(app, passport) {
return router;
}
I end up with the issue that the route code (./routes/auth.js) have no clue what passport is. (loded in the app as follows):
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
//Configuring the passports
require('./config/passport')(passport);
You'll be getting the error because you're not returning the router.
module.exports=function(app, passport) {
return router;
}
EDIT:
You won't be able to access the passport property because you're not passing it around or setting it anywhere. As I'm not sure how passport works (whether it acts as a singleton or not), so you have a couple of options in your routes file:
var passport = require('passport')
which may "just work", or
var passport; // at the top of your routes file
// your routes
module.exports = function(app, _passport) {
passport = _passport;
return router;
}
A third option is to wrap your entire routes in the exports method:
// your requires here
module.exports = function(app, passport) {
//So we can read the headers easily
router.use(bodyParser.json()); // support json encoded bodies
router.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
//Activating activator, so we can actively activate the actives
activator.init({user: activatorCfg, transport: activatorCfg.smtpUrl , from: activatorCfg.fromEmail, templates: activatorCfg.templatesDir});
//Lets start with our routes
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
return router;
}
I use express and express-session middleware to build a website, with session enabled. But some url such as /health-check' and/version-checkdo not need session, especially the/health-check`, which will generate a lot of useless session in db(the project use mongodb).I believe there is a good solution to solve the problem.
The following is a snippets of the session:
var session = require('express-session'),
passport = require('passport');
var app = express();
//other middleware.
// Express MongoDB session storage
app.use(session({
saveUninitialized: true,
resave: true,
secret: config.sessionSecret,
cookie: { maxAge: 2628000000 },
store: new mongoStore({
db: db.connection.db,
collection: config.sessionCollection
})
}));
// use passport session
app.use(passport.initialize());
app.use(passport.session());
//...
I suggest to create own middleware function and put there your session middleware as function, but with conditions e.g:
app.use(function(req, res, next){
if(...some condition...){//for example check url
//do something or nothing
next();//very important or request will freeze
} else {//otherwise run session
session({your options})(req, res, next);
}
});
instead your app.use(session())
in one custom middleware you can put any other middleware to add conditions. But when you want to wrap more then one middleware to single custom middleware be careful on 'next'. It can be use only once in middleware (multiple middlewares use use it multiple time). Then you have to create your own callback 'next'.
I have a simple, generic express app. It logs the req.sessionID whenever a certain route is hit. I would expect that refreshing the client page would result in the same sessionID being logged again. This works, if I've imported passport and added the passport middleware after the session middleware. If I either don't use passport at all, or I add passport middleware before the session middleware, then the sessionID is different every time.
I can accept that the ordering of middleware can be finicky. However, my app doesn't use passport at all, so I can't fathom why my app doesn't work if I don't require passport. Should passport be necessary for sessions to work?
//generic express initialization
var http = require('http');
var express = require('express');
var cookieParser = require('cookie-parser');
var passport = require('passport');
var session = require('express-session');
var app = express();
var server = http.createServer(app);
var sessionMiddleware = session({resave: false, saveUninitialized: false, secret: 'hunter2'});
app.use(cookieParser());
//This works:
app.use(sessionMiddleware);
app.use(passport.initialize());
//This doesn't:
app.use(passport.initialize());
app.use(sessionMiddleware);
Switch to resave: true, saveUninitialized: true
Unmodified sessions were not being saved, thus resulting in repeatedly generating new session IDs. Passport, however, was presumably doing some initialization on the session, meaning that the session was no longer unmodified.
Thanks to #Dodekeract and #Swaraj Giri for figuring the issue in their comments!