Monday, 12 June 2017

express session and passport: req.isAuthenticated() return false after login

I need to handle persistent session on an Angular app using express and passport on the backend. After a successful login, if I make an http call (using angular $http) to an express API which returns request.isAuthenticated(), it always returns false. This is not case when I login and make the http call to the API using Postman, in that case i got true.

This is my configuration on the server:

server.js

const
        express = require('express'),
        config = require("../config"),
        path = require('path'),
        bodyParser = require('body-parser'),
        cookiePraser = require('cookie-parser'),
        cors = require('cors'),
        winston = require("winston"),
        morgan = require("morgan"),
        mongoose = require("mongoose"),
        passport = require("passport"),
        session = require("express-session"),
        flash = require("connect-flash"),



let app = express(),
    server = require("http").Server(app),
    io = require("socket.io")(server);

const sessionKey = "mySessionKey";




/*
 * ---------------------------------------------------------------------------------------
 * app configuration
 * ---------------------------------------------------------------------------------------
 */

// Add headers
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', req.headers.origin);

    // Request methods you wish to allow
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    // Request headers you wish to allow
    res.setHeader('Access-Control-Allow-Headers', "Content-Type,X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5,  Date, X-Api-Version, X-File-Name");

    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader('Access-Control-Allow-Credentials', true);

    // Pass to next layer of middleware
    next();
});



app.use(morgan("dev")); 
app.use(bodyParser.json({limit: "50mb"}));
app.use(cookiePraser(sessionKey));    
app.use(express.static("public"));



app.use(session({
    secret: sessionKey,
    resave: true,
    saveUninitialized: true,
    cookie: {
        secure: false,
        httpOnly: false
    }
}));
app.use(passport.initialize());
app.use(passport.session()); 

require("./passportConfig")(passport); // passport configuration


app.get("api/test", function(req, res){
    return json({isAuthenticated: req.isAuthenticated()});
})

// [..]

passportConfig.js

const   LocalStrategy   =   require("passport-local").Strategy,
        User            =   require("./models/User");



module.exports = function(passport) {


    // used to serialize the user for the session
    passport.serializeUser(function(user, done) {
        done(null, user.id);
    });

    // used to deserialize the user
    passport.deserializeUser(function(id, done) {
        User.findById(id, function(err, user) {
            done(err, user);
        });
    });





    passport.use('local-signup', new LocalStrategy({

            usernameField : 'email',
            passwordField : 'password',
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },

        function(req, email, password, done) {

            // asynchronous
            // User.findOne wont fire unless data is sent back
            process.nextTick(function () {

                User.findOne({'local.email': email}, function (err, user) {
                    if (err)
                        return done(err);

                    // check to see if theres already a user with that email
                    if (user) {
                        return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
                    } else {

                        // if there is no user with that email
                        // create the user
                        let newUser = new User();

                        // set the user's local credentials
                        newUser.local.email = email;
                        newUser.local.password = newUser.generateHash(password);

                        // save the user
                        newUser.save(function (err) {
                            if (err)
                                throw err;
                            return done(null, newUser);
                        });
                    }

                });

            });

        }
    ));







    passport.use('local-login', new LocalStrategy({
            usernameField : 'email',
            passwordField : 'password',
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, email, password, done) { // callback with email and password from our form

            // find a user whose email is the same as the forms email
            // we are checking to see if the user trying to login already exists
            User.findOne({ 'local.email' :  email }, function(err, user) {
                // if there are any errors, return the error before anything else
                if (err)
                    return done(err);

                // if no user is found, return the message
                if (!user)
                    return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash

                // if the user is found but the password is wrong
                if (!user.validPassword(password))
                    return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata

                // all is well, return successful user
                return done(null, user);
            });

        }
    ));





};

After a login I can see the cookie connect.sid has been set, but then if I try to call "api/test" route using angular $http I get always false (it returns true if I use Postman). Any suggestion on how to fix this?



via revy

No comments:

Post a Comment