How to get user session from passport.js? - node.js

My problem is with 2 files in my project: server.js (where i'am going to use the user session) and route.js(define my routes).
I've managed to get the user session in routes.js with req.user() but not in app.js with
here is the code of route.js:
module.exports = function(app, passport) {
// LOGIN
// show the login form
app.get('/', function(req, res) {
// render the page and pass in any flash data if it exists
res.render('login.ejs', { message: req.flash('loginMessage') });
});
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}),
function(req, res) {
if (req.body.remember) {
req.session.cookie.maxAge = 1000 * 60 * 3;
} else {
req.session.cookie.expires = false;
}
res.redirect('/');
});
// PROFILE SECTION =========================
// we will want this protected so you have to be logged in to visit
// we will use route middleware to verify this (the isLoggedIn function)
app.get('/profile', isLoggedIn, function(req, res) {
var a = req.user.Email;
console.log(a);
res.render('profile.ejs', {
user : req.user // get the user out of session and pass to template
});
});
// =====================================
// LOGOUT ==============================
// =====================================
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
// route middleware to make sure
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
and server.js :
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
var passport = require('passport');
var flash = require('connect-flash');
var server = require('http').createServer(app);
// configuration ===============================================================
require('./config/passport')(passport); // pass passport for configuration
app.configure(function() {
// set up our express application
app.use(express.logger('dev')); // log every request to the console
app.use(express.cookieParser()); // read cookies (needed for auth)
app.use(express.bodyParser()); // get information from html forms
// Make the files in the public folder available to the world
app.use(express.static(__dirname + '/public'));
// Tell express where it can find the templates
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs'); // set up ejs for templating
// required for passport
app.use(express.session({ secret: 'chiftestisalwaysrunning' } )); // 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
});
// routes ======================================================================
require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
/*i want to get the user session*/
// launch ======================================================================
server.listen(port);
console.log('The magic happens on port ' + port);

Related

Possible to log in specific user with Passport Strava strategy without log in screen?

I want to have an online map which publicly loads and shows all my activities from my Strava account.
I have found a web app on GitHub which does what I want but the user has to log in with the Strava log in screen before he than can see his own activities: https://github.com/nsynes/ActivityMap
It seems it uses Passport Strava to authenticate with Strava: https://www.passportjs.org/packages/passport-strava-oauth2/
Is it possible to adjust the script so it always logs in automatically my account and than shows my activities publicly to everyone who visits the map?
The full script is here: https://github.com/nsynes/ActivityMap/blob/master/activity-map-app.js
My STRAVA_CLIENT_ID and STRAVA_CLIENT_SECRET are from my Strava account and saved in a .env file.
const express = require('express')
const passport = require('passport')
const util = require('util')
const StravaStrategy = require('passport-strava-oauth2').Strategy
const dotenv = require('dotenv');
const path = require('path');
const cookieParser = require('cookie-parser')
const bodyParser = require('body-parser');
const session = require('express-session');
var strava = require('strava-v3');
const decode = require('geojson-polyline').decode
const geodist = require('geodist');
dotenv.config();
const port = process.env.PORT || 3000
const app = express();
// configure Express
//app.use(express.logger());
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: false }));
//app.use(express.methodOverride());
app.use(session({
secret: 'monkey tennis',
resave: true,
saveUninitialized: true,
maxAge: 1800 * 1000
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/css', express.static(path.join(__dirname, 'css')));
app.use('/fontawesome', express.static(path.join(__dirname, 'fontawesome')));
app.use('/js', express.static(path.join(__dirname, 'js')));
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
// Passport session setup.
passport.serializeUser(function(user, done) { done(null, user) });
passport.deserializeUser(function(obj, done) {done(null, obj) });
passport.use(new StravaStrategy({
clientID: process.env.STRAVA_CLIENT_ID,
clientSecret: process.env.STRAVA_CLIENT_SECRET,
callbackURL: "/auth/strava/callback"
},
function(accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// To keep the example simple, the user's Strava profile is returned to
// represent the logged-in user. In a typical application, you would want
// to associate the Strava account with a user record in your database,
// and return that user instead.
return done(null, profile);
});
}
));
app.get('/', ensureAuthenticated, function(req, res){
pagePath = path.join(__dirname, '/index.html');
res.sendFile(pagePath);
});
app.get('/userPhoto', ensureAuthenticated, function(req, res){
if ( req.user ) {
res.json({ 'photo': req.user.photos[req.user.photos.length-1].value });
} else {
res.sendStatus(404);
}
});
// Use passport.authenticate() as route middleware to authenticate the
// request. Redirect user to strava, then strava will redirect user back to
// this application at /auth/strava/callback
app.get('/auth/strava',
passport.authenticate('strava', { scope: ['activity:read'], approval_prompt: ['force'] }),
function(req, res){
// The request will be redirected to Strava for authentication, so this
// function will not be called.
});
// GET /auth/strava/callback
// Use passport.authenticate() as route middleware to authenticate the
// request. If authentication fails, the user will be redirected back to the
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
app.get('/auth/strava/callback',
passport.authenticate('strava', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
app.get('/logout', function(req, res){
req.logout();
res.cookie("connect.sid", "", { expires: new Date() });
res.render('login', { user: req.user });
});
app.get('/login', function(req, res){
res.render('login', { user: req.user });
});

nodejs: "req.session.save is not a function" error during authentication

I am using PassportJS to authenticate users in my application. After a user logs in, the session is created, but soon after being redirected, the session appears to become undefined once again because it hasn't been saved. I found online that often times with redirects, the redirect completes before the session is saved, and so it's as if authentication never happened. The apparent solution is to use the req.session.save function so that redirects will only happen after the session is saved. However, I am getting an error log of "TypeError: req.session.save is not a function." Can somebody please help?
Here is my code for app.js.
var express = require('express'),
passport = require('passport'),
session = require('express-session'),
bodyParser = require('body-parser'),
RedisStore = require('connect-redis')(session),
redis = require('redis'),
logger = require('morgan'),
errorHandler = require('express-error-handler'),
site = require('./site'),
oauth2 = require('./oauth2'),
port = process.env.PORT || 8080;
var app = express();
var redisClient = redis.createClient(8080, 'localhost');
// use sessions for tracking logins
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: true,
store: new RedisStore({
client: redisClient,
host: "pub-redis-14280.us-central1-1-1.gce.garantiadata.com",
port: 12543,
ttl: 260
})
}));
app.use(logger('dev'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json({ type: 'application/json' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(errorHandler({ dumpExceptions: true, showStack: true }));
// use ejs as file extension for views
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/views'));
// use passport
require('./auth');
// Account linking
app.get('/', site.index);
app.get('/login', site.loginForm);
app.post('/login', site.login);
app.get('/logout', site.logout);
app.get('/authorize', oauth2.authorization);
app.post('/authorize/decision', oauth2.decision);
// set up local server
if (module === require.main) {
// [START server]
// Start the server
var server = app.listen(process.env.PORT || 8080, function () {
var port = server.address().port;
console.log('App listening on port %s', port);
});
// [END server]
}
module.exports = app;
site.js:
var passport = require('passport');
var login = require('connect-ensure-login');
// get layout
exports.index = function (req, res) {
console.log("layout loaded");
res.render('layout');
}
// get login form
exports.loginForm = function (req, res) {
console.log("login page loaded");
res.render('login');
}
// post login form
exports.login = [
passport.authenticate('local'),
function (req, res) {
req.session.save(function (err) {
res.redirect('/');
});
}
]
// logout
exports.logout = function (req, res) {
req.logout();
res.redirect('/');
}
Passport serialize/deserialize user:
passport.serializeUser(function(id, done) {
console.log("serializing user");
done(null, id);
});
passport.deserializeUser(function(id, done) {
console.log("deserializing user");
done(null, id);
});
In my passport authentication, I return the user id for simplicity, since that's all I need to represent users in my system.
In case anybody else is still having this issue (like me), try following Nathan's comment above and debug your connection to your redis/mongo/etc store.
What worked for me was I had my redis host set to http://localhost so I swapped it to 127.0.0.1 (local development of course) and everything immediately worked.

Exporting middleware globally to all routes

So I have been working with PassportJS in adding authentication to my site. I am interested in selectively displaying content that reflects whether or not a user is logged in or if he/she is an owner of a document.
I have the following files
app.js (entry point)
//Express set up
let express = require("express");
app = express();
serverPort = 8000;
io = require('socket.io')();
//BodyParser set up
bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: true }));
//Mongoose set up
mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/Woof");
//Models settings
Dog = require("./models/dog");
User = require("./models/user");
//Seed file set up and run!
seed = require("./models/seed");
seed();
//Routes
app.use('/public', express.static(__dirname + '/public'));
app.use(require('./routes/dogOwners'));
app.use(require('./routes/landing'));
app.use(require('./routes/loginAndRegister'));
app.use(require('./routes/map'));
app.use(require('./routes/dog'));
//req.user avalaible to all routes
app.use(function(req,res,next){
res.locals.currentUser = req.user;
next();
});
//App settings
app.set('port', serverPort);
app.set('view engine', 'ejs');
app.set('views', 'views');
app.set('sockets', []);
//Servloger listen:
let server = app.listen(app.get('port'), function() {
console.log('Listening on port ' + app.get('port'));
});
loginAndRegistration.js These are the authentication routes
let express = require('express');
router = express.Router({ mergeParams: true });
User = require("../models/user")
//AUTHENTICATION
let passport = require("passport");
LocalStratergy = require("passport-local");
//PASSPORT CONFIGURATION
app.use(require("express-session")({
secret: "I wanna go poopie",
resave: false,
saveUninitialized: false,
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(function(req,res,next){
res.locals.currentUser = req.user;
next();
});
passport.use(new LocalStratergy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
router.get('/login', function(req,res){
res.render('login');
});
router.post('/login', passport.authenticate('local', {
successRedirect: "/main",
failureRedirect: "/login",
}), function(req, res) {
});
router.get('/logout', function(req,res){
req.logout();
res.redirect("/");
});
router.get('/register', function(req, res) {
res.render('register', {});
});
router.post("/register", function(req, res) {
User.register(new User({ username: req.body.username }), req.body.password, function(error, newlyCreatedUser) {
if (error) {
console.log("COULD NOT REGISTER USER IN THE POST ROUTE");
res.render("register");
console.log(error);
} else {
passport.authenticate("local")(req, res, function() {
let user = req.body.user;
newlyCreatedUser.name = user.name;
newlyCreatedUser.nickname = user.nickname;
newlyCreatedUser.address = user.address;
newlyCreatedUser.email = user.email;
newlyCreatedUser.numberOfDogs = user.numberOfDogs;
newlyCreatedUser.url = "/user/" + newlyCreatedUser.id;
newlyCreatedUser.save(function(error, savedUser) {
console.log("USER REGISTERED");
res.render('maps', {
gmapsCredential: credentials.gmaps,
'authorized': true
});
});
});
}
});
});
function isLoggedIn (req,res,next){
if(req.isAuthenticated()){
return next();
}
res.redirect("/login");
}
module.exports = router;
I wanna be able to call isLoggedIn in all my routes, but I can only use it in the auth routes. How do I selectively export that function alone to all my routes? I also wanna be able to refer to the varaible currentUser in all my .ejs files, however it only works in .ejs files associated with the auth routes. How do I check for currentUser in all my .ejs files?
The crux of your problems are you’ve got too much buried in your loginAndRegistration.js file.
First and foremost, if you want to run isLoggedIn for every route you need to make sure Passport is configured first i.e.
app.use(passport.initialize());
app.use(passport.session());
app.use(function(req,res,next){
res.locals.currentUser = req.user;
next();
});
passport.use(new LocalStratergy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
Needs to be setup before you configure any auth middleware. This will also solve your .ejs problem as user will now be getting serialised for every route and not just the auth ones.
Finally, you can configure your middleware before any routes you want to enforce authentication on
app.use(isLoggedIn);

Express router create a new session not wanted

I am doing a react project using express and passport-local for the authentication part based on this tutorial :
https://scotch.io/tutorials/easy-node-authentication-setup-and-local
The authentification work very well, I added the express router to define my routes for my api, but when I call for example "/api/myroute" the router of express creates an other session and I lose the user, so my function isLoggedIn blocks the call of my controllers because there is no user in this new session. So my question is : Why the router recreate a session ? What it is wrong in my configuration ? Here is my code :
//server.js
var path = require('path');
var webpack = require('webpack');
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var config = require('./webpack.config');
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var configDB = require('./config/database.js');
var router = express.Router();
// configuration ===============================================================
mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
// set up our express application
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
app.set('view engine', 'ejs'); // set up ejs for templating
// required for passport
app.use(session({ secret: 'secret' })); // 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
var compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }));
app.use(webpackHotMiddleware(compiler));
app.use('/plugins/bootstrap', express.static(path.join(__dirname, './plugins/bootstrap')));
app.use('/plugins/jquery', express.static(path.join(__dirname, './plugins/jquery')));
app.use('/plugins/font-awesome', express.static(path.join(__dirname, './plugins/font-awesome')));
// all of our routes will be prefixed with /api
app.use('/api', router);
// routes ======================================================================
require('./api/routes.js')(app, passport,router); // load our routes and pass in our app and fully configured passport
// launch ======================================================================
app.listen(port, function(error) {
if (error) {
console.error(error)
} else {
console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port)
}
});
console.log('The magic happens on port ' + port);
And here is my routes.js :
module.exports = function(app, passport,router) {
var MyController = require("../api/controllers/mycontroller");
// =====================================
// HOME PAGE (with login links) ========
// =====================================
app.get('/', function(req, res) {
console.log("welcome")
res.render('index.ejs', { message: ""}); // load the index.ejs file
});
// =====================================
// LOGIN ===============================
// =====================================
// show the login form
app.get('/login', function(req, res) {
console.log("login")
// render the page and pass in any flash data if it exists
res.render('index.ejs', { message: req.flash('loginMessage') });
});
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/welcome', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
// =====================================
// SIGNUP ==============================
// =====================================
// show the signup form
app.get('/signup', function(req, res) {
console.log("signup")
// render the page and pass in any flash data if it exists
res.render('signup.ejs', { message: req.flash('signupMessage') });
});
// process the signup form
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/welcome', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
// process the signup form
// app.post('/signup', do all our passport stuff here);
// =====================================
// LOGOUT ==============================
// =====================================
app.get('/logout', function(req, res) {
console.log("logout")
req.logout();
res.redirect('/');
});
router.get('/myroute', isLoggedIn, function(req, res) {
//HERE the router recreate a session and req.user is now undefined why ?
MyController.getAllObjects(req,res);
});
// =====================================
// HOME SECTION =====================
// =====================================
// we will want this protected so you have to be logged in to visit
// we will use route middleware to verify this (the isLoggedIn function)
app.get('*', isLoggedIn, function(req, res) {
console.log("HOME")
res.render('home.ejs', {
user : req.user // get the user out of session and pass to template
});
});
};
// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
console.log("redirect because not log in")
// if they aren't redirect them to the home page
res.redirect('/');
}
The function for login, logout, signin... are a copy paste of the tutorial.
You seem to be using the fetch library. This library does not include the domain cookies by default, so in order to work your request should look like this:
fetch('/api/myroute', {
credentials: 'same-origin' // This is the line you are missing
}).then(response => response.json())
.then(json => {
dispatch({
type: types.MY_ACTION, forms: json, receivedAt: Date.now()
})
})
See this link for more information.

How to use session in ExpressJS?

As i understood i can use sessions only inside the requests, something like:
app.get('/', function (req, res) {
if (req.session.log_in)
res.render('index.html', config);
else
res.render('authorization.html', config);
});
But if i have for example 20 or more routes so i need to write authorization check in each route? Is there something global with sessions like in php that i could check sessions before all routes and determinate and decide on follow-up actions?
Express allows a middle parameter of middleware called for that route. Use an authorization system like Passport and call it like this:
app.get('/account', ensureAuthenticated, function(req, res){
res.render('account', { user: req.user });
});
We can manage session in ExpressJS using express-session package. If you are running it in shared resource, you need to use Redis or something to keep it consistent.
Server.js
var express = require('express');
var session = require('express-session');
var bodyParser = require('body-parser');
var app = express();
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.use(session({secret: 'ssshhhhh'}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
var sess;
app.get('/',function(req,res){
sess=req.session;
//Session set when user Request our app via URL
if(sess.email)
{
/*
* This line check Session existence.
* If it existed will do some action.
*/
res.redirect('/admin');
}
else{
res.render('index.html');
}
});
app.post('/login',function(req,res){
sess=req.session;
//In this we are assigning email to sess.email variable.
//email comes from HTML page.
sess.email=req.body.email;
res.end('done');
});
app.get('/admin',function(req,res){
sess=req.session;
if(sess.email)
{
res.write('
<h1>Hello '+sess.email+'</h1>
');
res.end('Logout');
}
else
{
res.write('
<h1>Please login first.</h1>
');
res.end('Login');
}
});
app.get('/logout',function(req,res){
req.session.destroy(function(err){
if(err){
console.log(err);
}
else
{
res.redirect('/');
}
});
});
app.listen(3000,function(){
console.log("App Started on PORT 3000");
});
Read complete tutorial here : http://codeforgeek.com/2014/09/manage-session-using-node-js-express-4/

Resources