passport.js not passing user to session - javascript

I'm trying to create an app with passport.js, node and sequelize.
But, passport is not returning the user in the session as expected.
When I log req.session I get this:
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true,
secure: true } }
when I log req.session.passport I get undefined.
How can I fix this?
This is my server.js:
const express = require('express');
const load = require('express-load');
const passport = require('passport');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const session = require('express-session');
// var app = express();
var app = module.exports = express();
// read cookies (needed for auth)
app.use(cookieParser());
// get information from html forms
app.use(bodyParser());
//set session
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 'asdasdsada',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
// required for passport
app.use(passport.initialize());
app.use(passport.session({
secret: 'adsdssa',
name: 'sadasd',
proxy: true,
resave: true,
saveUninitialized: true
}));
And this is my passport.js:
var LocalStrategy = require('passport-local').Strategy;
var SlackStrategy = require('passport-slack').Strategy;
var User = require('../models/index').User;
var mysql = require('mysql');
var connection = mysql.createConnection({
host : process.env.MYSQL_HOST,
user : process.env.MYSQL_USER,
password : process.env.MYSQL_PASSWORD,
database : process.env.MYSQL_DB
});
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
console.log('-----------serialize');
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log('----------deserialize');
Model.User.findOne({
where: {
'id': id
}
}).then(function (user) {
if (user == null) {
done(new Error('Wrong user id.'));
}
done(null, user);
})
});
passport.use('slack', new SlackStrategy({
clientID: process.env.SLACK_ID,
clientSecret: process.env.SLACK_SECRET,
callbackURL: process.env.SLACK_REDIRECT,
scope: "incoming-webhook users:read"
},
function(accessToken, refreshToken, profile, done) {
var values = {
where: { slack_id: profile.id },
defaults: {slack_id: profile.id, name: profile.displayName}
};
User.findOrCreate(values)
.spread(function(user, created) {
return done(null,user);
});
}
));
And these are the routes I'm using:
app.get('/auth/slack',
passport.authorize('slack'));
app.get('/auth/slack/callback',
passport.authorize('slack', { failureRedirect: '/login' }),
function(req, res) {
//Successful authentication, redirect home.
console.log(req.session);
console.log(req.session.passport);
res.redirect('/dashboard');
}
);

I had the same problem and solved it.
Just remove
secure: true
for session like that
//set session
app.use(session({
secret: 'asdasdsada',
resave: false,
saveUninitialized: true
}))
It should works Also you can see simple example of passport-local here
https://github.com/passport/express-4.x-local-example

Related

Passport.authenticate() gets stucks

I am trying to make a "Connect with Twitter" feature for my website, and it is the first time that I use Passport.js.
I have a problem since a while now : when trying the api, the passport.authenticate function of the /twitter/callback page gets stucks and I can't do anything to solve this problem
I am running my app on my localhost system. Here is my code for the index.js page. The home.ejs just contains a template for EJS where I show the username.
var express = require('express');
var app = express();
const cookieParser = require('cookie-parser');
app.use(cookieParser('thissecretrocks'));
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
const session = require('express-session');
app.use(session({
resave: true,
saveUninitialized: true,
secret: 'bla bla bla'
}));
const mongoose = require('mongoose');
mongoose.connect('mongodb+srv://Something', {useNewUrlParser: true, useUnifiedTopology: true});
const db = {};
db.users = require('./db/users');
const passport = require('passport');
app.use(passport.initialize());
app.use(passport.session());
const Twitter = require('passport-twitter');
var Strategy = require('strategy');
const TwitterStrategy = Twitter.Strategy;
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
db.users.findById(id, function (err, user) {
done(err, user);
});
});
passport.use(new TwitterStrategy({
consumerKey: '5KSomethingMx',
consumerSecret: 'tld1Something6M2q',
callbackURL: "http://127.0.0.1:3000/auth/twitter/callback",
},
function(token, tokenSecret, profile, cb) {
console.log(profile);
/*const newUser = new db.users({
twitter: profile.id
});
newUser.save();*/
}
));
app.use('/cdn', express.static('cdn'));
app.get('/', function(req, res) {
res.render('home.ejs', {username: req.user.username});
});
app.get('/fail', function(req, res) {
console.log('FAIL');
res.render('home.ejs', {username: 'req.user.username'});
});
app.get('/auth/twitter', passport.authenticate('twitter'));
app.get('/auth/twitter/callback', passport.authenticate('twitter', { failureRedirect: '/fail' }), function(req, res) {
res.redirect('/');
});
app.listen(3000);

Express could not store cookie

I am trying to store a login-session into a cookie when a user login in via username/passport, so the server knows the user is logged in. But the cookie will never be set.
Here is the relevant code:
index.js:
if (process.env.NODE_ENV !== 'production') {
require("dotenv").config();
}
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.json({ limit: "16mb", extended: true }));
app.use(bodyParser.urlencoded({ extended: true, limit: "16mb" }));
const session = require("express-session");
app.use(
session({
secret: "thisIsMySecretMessageHowWillYouGuessIt",
resave: true,
saveUninitialized: true,
cookie: {
sameSite: 'none',
httpOnly: true,
secure: true
},
})
);
const passport = require("passport");
app.use(passport.initialize());
app.use(passport.session());
const cookieParser = require("cookie-parser");
app.use(cookieParser());
const cors = require("cors");
const whitelist = env.process.CLIENT_URL;
app.use(cors({ origin: whitelist, credentials: true }));
auth.js:
const cookieKey = "sid";
const md5 = require("md5");
const bcrypt = require("bcrypt");
const redis = require("redis");
const client = redis.createClient(process.env.REDIS_URL);
const cookieOption = { maxAge: 3600 * 1000, httpOnly: true, sameSite: 'none', secure: true};
login = async (req, res) => {
const sessionKey = md5(
getSecretMessage() + new Date().getTime() + user.username
);
client.hmset("sessions", sessionKey, JSON.stringify(user), function(err) {
if (err) throw err;
});
// this sets a cookie
res.cookie(cookieKey, sessionKey, cookieOption); // expire after 60 mins
res.send({ username: user.username, result: "success" });
};
isLoggedIn = async (req, res, next) => {
if (
(req.cookies === undefined || req.cookies[cookieKey] === undefined) &&
!req.isAuthenticated()
) {
res.sendStatus(401);
return;
}
};
The req.cookies['sid'] will always be undefined, so the server would return 401 status.
For the react client, the 'credentials' has been set to 'include'.
Things I tried:
Flipping around the 'secure' values in the cookie option in both index.js and auth.js
Used 'express-samesite-default' package
One point to notice is that the functionality was working half-year ago, there might be some dependencies update so it changed the cookie.
You could use local storage.Local storage saves on the clients device and is accessible using localStorage.getItem('key') and you can add items by using the localStorage.setItem('key', 'value').

Passport.js's req.isAuthenticated() always return false

Thats my code:
server.js:
require('dotenv').config()
var fs = require('fs')
var express = require('express')
var app = express()
var helmet = require('helmet')
var router = require('./router')
var session = require('express-session')
var passport = require('passport')
var cookie = require('cookie-parser')
var redis = require('redis').createClient(process.env.REDIS_PORT)
var redisStore = require('connect-redis')(session)
app.use(helmet())
app.use(cookie())
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(passport.initialize())
app.use(passport.session())
app.use(session({
store: new redisStore({client: redis}),
secret: 'rior124jybtyokipoev5432rtoe34wpta',
cookie: {
path: '/',
httpOnly: true,
maxAge: 1000*60*60*24*365,
secure: false
},
resave: false,
saveUninitialized: false
}))
app.use(router)
require('./config/passport');
app.listen(process.env._PORT, () => {
console.log('[Info][Backend] Backend http serve succesfuly started! Port: '+process.env._PORT);
})
router/index.js:
var router = require('express').Router()
var auth = require('../lib/auth_mw')
var fs = require('fs')
router.use(require('./logging'))
router.use(require('./news'))
router.get('/', (req, res) => {
res.contentType('text/plain')
res.end(fs.readFileSync(__dirname+'/../siteinfo.txt'))
})
router.get('/private', auth, (req, res) => {
res.end('private')
})
module.exports = router
config/passport.js:
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
var users = require('../models').users
passport.serializeUser(function(user, done) {
console.log('serialize: ', user);
done(null, user.email);
});
passport.deserializeUser(function(email, done) {
console.log('deserialize: ', email);
users.findOne({
attributes: [
'email'
],
where: {
email
}
}).then(user => {
done(null, user.email === email ? user.dataValues : false);
})
});
passport.use('local',
new LocalStrategy({ usernameField: 'email' }, async function(
email,
password,
done
) {
let user = await users.findOne({
attributes: [
'email',
'password'
],
where: {
email,
password
}
})
if (user.dataValues.email) {
return done(null, user.dataValues);
} else {
return done(null, false);
}
})
);
Login always succesfull, but when i'm trying to go to /private, deserialize function doesn't called! I found many resolves on the net, but doesn't help. Please, suggest as many resolves as you know
P.S. I use sequelize as a database driver (idk maybe it's important)
This query will return the correct user, So You don't need to check the output again.
users.findOne({
attributes: [
'email'
],
where: {
email
}
})
Try done(null, user.dataValues); instead of done(null, user.email === email ? user.dataValues : false);

Session is not working + express

I am using express-session in my app. What i have tried is (POC):.
server.js
app.use(session({
secret: 'pal!lap789',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
key: 'user_sid',
resave: false,
cookie: { secure: false, httpOnly: false }
}));
app.get('/abcd', sessionChecker, function(req, res){
res.send("hiiiii");
});
app.get('/session', (req, res) => {
req.session.user = "subbuvlb#gmail.com";
res.send("hgdhjdgjds")
});
Its working properly,
But when i try to integrate with my project ,its not working.
app.use(session({
secret: 'pal!lap789',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
key: 'user_sid',
resave: false,
cookie: { secure: false, httpOnly: false }
}));
var usersRouter = require('./router/users');
app.use('/users', usersRouter);
router/user.js
const express = require('express'); -------------> New express instantiated.
const router = express.Router();
router.post('/register', (req, res, next) => {
req.session.user = "emailid"
});
What i am trying to achieve is have to check if user session is there for each resquest,
so i modified my server.js file as follows:
app.use(session({
secret: 'pal!lap789',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
key: 'user_sid',
resave: false,
cookie: { secure: false, httpOnly: false }
}));
var usersRouter = require('./router/users');
app.use('/users', usersRouter);
var sessionChecker = (req, res, next) => {
console.log(req.session.user) --------------------------->Undefined
if (req.session.user && req.cookies.user_sid) {
next();
} else {
res.redirect('/login');
}
};
var usersRouter = require('./router/users');
app.use('/users',sessionChecker, usersRouter);
Why the req.user.undefined if i specify router files in server.js. I think i explained clearly, ready to give more input if needed. Please provide ur ideas. Thanks in advance.
define global variable in your server.js file
global.express = require('express');
global.app = express();
global.session = require('express-session');
app.use(session({
secret: 'pal!lap789',
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
key: 'user_sid',
resave: false,
cookie: { secure: false, httpOnly: false }
}));
var sessionChecker = (req, res, next) => {
if (req.session.user && req.cookies.user_sid) {
next();
} else {
res.redirect('/login');
}
};
var usersRouter = require('./router/users');
app.use('/users',sessionChecker, usersRouter);
in your router/user.js
const router = express.Router(); // use global express defined in server.js
router.post('/register', (req, res, next) => {
req.session.user = "emailid"
});
Finally i got the trick,
I am checking from Angular.js front-end, by default Angular will not include Cookies, so i have set {"withCredentials": "true"} in each Request from Angular Front-end.

Messenger Chatbot - account linking and Facebook login with Passport

Been having some trouble for the past week getting this link to work. Feel like I'm misunderstanding something from the flow.
What I'm struggling with was implementing the passport with passport-facebook. I want to include the passport.authenticate inside the same route as the account linking. Currently only managed to separate the two processes and having two logins. Looking to merge them.
As can be seen here http://recordit.co/osdMl0MUCL
Is there no way to do the passport.authenticate inside the link route ? Been trying with no success.
Tried to move the passport.authenticate inside app.get('/authorize but don't know how to handle the const redirectURISuccess = ${redirectURI}&authorization_code=${authCode};
res.redirect(redirectURISuccess);
I'm thinking would need to do this inside the app.get(/auth/fb/callback' ... but not sure how.
This is what I have currently
'use strict';
require('dotenv').config();
const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
const http = require('http');
const port = '3000';
const passport = require('passport');
const FacebookStrategy = require('passport-facebook').Strategy;
const fbConfig = require('./oauth');
const cookieParser = require('cookie-parser');
const session = require('express-session');
// used to serialize the user for the session
// Not using these yet
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (obj, done) {
done(null, obj);
});
const Botly = require('botly');
const botly = new Botly({
accessToken: process.env.ACCESS_TOKEN,
verifyToken: '123123321' // the verification token you provided when defining the webhook in facebook
});
const app = express();
// Listen on the account link event
botly.on('account_link', (sender, message, link) => {
// Continue conversation
console.log('CONFIRMED AUITH', link);
botly.sendText({
id: sender,
text: (link.status === 'unlinked') ? 'sorry to see you go' : 'Welcome'
});
botly.sendButtons({
id: sender,
text: 'Please Login Again :-) This time for real',
buttons: [ botly.createAccountLinkButton(`https://${process.env.LOGIN_DOMAIN}/auth/fb/?senderId=' + sender/`) ]
});
});
botly.on('message', (senderId, message, data) => {
const text = `echo: ${data.text}`;
botly.sendText({
id: senderId,
text: text
});
botly.sendButtons({
id: senderId,
text: 'Please Login :)',
buttons: [ botly.createAccountLinkButton(`https://${process.env.LOGIN_DOMAIN}/authorize/`), botly.createAccountUnLinkButton() ]
});
});
app.use(bodyParser.json());
app.use('/', router);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({ secret: 'its_my_secret', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use('/webhook', botly.router());
app.set('port', port);
/*
* This path is used for account linking. The account linking call-to-action
* (sendAccountLinking) is pointed to this URL.
*
*/
app.get('/authorize', function (req, res) {
// Passport setup
passport.use('facebook', new FacebookStrategy({
clientID: fbConfig.facebook.clientID,
clientSecret: fbConfig.facebook.clientSecret,
callbackURL: fbConfig.facebook.callbackURL,
profileFields: [ 'id', 'displayName', 'email' ]
},
// facebook will send back the tokens and profile
function (request, access_token, refresh_token, profile, done) {
// asynchronous
process.nextTick(function () {
console.log('WATCH THIS: ', profile);
return done(null, profile);
});
}));
console.log('%%%%%%%% AccountLinking Testing');
const accountLinkingToken = req.query.account_linking_token;
const redirectURI = req.query.redirect_uri;
console.log('%%%%%%%% /authorize called with accountLinkingToken %s, redirectURI %s', accountLinkingToken, redirectURI);
// Authorization Code should be generated per user by the developer. This will
// be passed to the Account Linking callback.
const authCode = '1234567890';
// Redirect users to this URI on successful login
const redirectURISuccess = `${redirectURI}&authorization_code=${authCode}`;
res.redirect(redirectURISuccess);
});
app.get('/auth/fb', (req, res, next) => {
req.session.senderId = req.query.senderId;
passport.authenticate('facebook', { scope: [ 'email' ] },
{
state: {
senderId: req.query.senderId // senderId will be used after auth to reply to the user
}
})(req, res, next);
});
// Redirection after login
app.get('/auth/fb/callback',
passport.authenticate('facebook', {
successRedirect: `https://m.me/${process.env.app_name}`, // The webview I want to open if user logs in
failureRedirect: '/somePage' // redirect to Messenger if failure
}));
const server = http.createServer(app);
server.listen(port);
I solved it I think. Probably not the best way to go about it though. I'm passing the account linked redirect URI to the callback route and resolving the passport.authenticate in there redirecting if needed.
'use strict';
require('dotenv').config();
const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
const LINKED = {};
const http = require('http');
const port = '3000';
const passport = require('passport');
const FacebookStrategy = require('passport-facebook').Strategy;
const fbConfig = require('./oauth');
const cookieParser = require('cookie-parser');
const session = require('express-session');
// used to serialize the user for the session
// Not using these yet
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (obj, done) {
done(null, obj);
});
const Botly = require('botly');
const botly = new Botly({
accessToken: process.env.ACCESS_TOKEN,
verifyToken: '123123321' // the verification token you provided when defining the webhook in facebook
});
const app = express();
// Listen on the account link event
botly.on('account_link', (sender, message, link) => {
// Continue conversation
console.log('CONFIRMED AUITH', link);
botly.sendText({
id: sender,
text: (link.status === 'unlinked') ? 'sorry to see you go' : 'Welcome'
});
});
botly.on('message', (senderId, message, data) => {
const text = `echo: ${data.text}`;
botly.sendText({
id: senderId,
text: text
});
botly.sendButtons({
id: senderId,
text: 'Please Login :)',
buttons: [ botly.createAccountLinkButton(`https://${process.env.LOGIN_DOMAIN}/authorize/?senderId=' + senderId/`), botly.createAccountUnLinkButton() ]
});
});
app.use(bodyParser.json());
app.use('/', router);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({ secret: 'its_my_secret', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use('/webhook', botly.router());
app.set('port', port);
// Passport setup
passport.use('facebook', new FacebookStrategy({
clientID: fbConfig.facebook.clientID,
clientSecret: fbConfig.facebook.clientSecret,
callbackURL: fbConfig.facebook.callbackURL,
profileFields: [ 'id', 'displayName', 'email' ]
},
// facebook will send back the tokens and profile
function (request, access_token, refresh_token, profile, done) {
// asynchronous
process.nextTick(function () {
return done(null, profile);
});
}));
/*
* This path is used for account linking. The account linking call-to-action
* (sendAccountLinking) is pointed to this URL.
*
*/
app.get('/authorize', function (req, res, next) {
req.session.senderId = req.query.senderId;
console.log('%%%%%%%% AccountLinking Testing');
const accountLinkingToken = req.query.account_linking_token;
const redirectURI = req.query.redirect_uri;
console.log('%%%%% /authorize called with accountLinkingToken %s, redirectURI %s', accountLinkingToken, redirectURI);
// Authorization Code should be generated per user by the developer. This will
// be passed to the Account Linking callback.
const authCode = '1234567890';
// Redirect users to this URI on successful login
const redirectURISuccess = `${redirectURI}&authorization_code=${authCode}`;
LINKED.redirect = redirectURISuccess;
console.log('redirect to this ', redirectURISuccess);
passport.authenticate('facebook', { scope: [ 'email' ] },
{
state: {
senderId: req.query.senderId // senderId will be used after auth to reply to the user
}
})(req, res, next);
});
// Redirection after login
app.get('/auth/fb/callback', (req, res, next) => {
passport.authenticate('facebook', (err, user, info) => {
if (err) { return next(err); }
if (!user) {
console.log('bad', info);
return res.redirect(LINKED.redirect);
}
console.log('good');
LINKED.user = user;
})(req, res, next);
res.redirect(LINKED.redirect);
});
const server = http.createServer(app);
server.listen(port);

Categories