Related
Passport is being used to log in via Discord in order to access a Dashboard. Main problem is the logout though, worked before passport v.0.6.0, but now it doesn't. req.logout(); now needs a callback function (see here) to work, but when I now access /logout
on the website I get Error: Login sessions require session support. Did you forget to use 'express-session' middleware?
settings.json
{
"website": {
"support": "https://discord.gg/xxxxxxx",
"domain": "http://localhost:5991"
},
"config": {
"port": 5991,
"callback": "http://localhost:5991/callback",
"clientID": "botId",
"secret": "OAuth2 Secret"
}
}
index.js
const express = require('express');
const url = require('url');
const path = require('path');
const ejs = require('ejs');
const passport = require('passport');
const bodyParser = require('body-parser');
const Strategy = require('passport-discord').Strategy;
const settings = require('./settings.json');
const logger = require('silly-logger');
const favicon = require('serve-favicon');
module.exports = client => {
// website config backend
const app = express();
const session = require('express-session');
const MemoryStore = require("memorystore")(session);
// middleware
app.use(session({
secret: `superdupersecret`,
store: new MemoryStore({ checkPeriod: 86400000 }),
resave: false,
saveUninitialized: false,
}));
app.use(favicon(path.join(__dirname, 'public/assets', 'favicon.ico')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true,
}));
app.use(express.json());
app.use(express.urlencoded({
extended: true,
}));
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "./views"));
// loading public
app.use('/public', express.static(__dirname + '/public'));
app.use(passport.initialize());
app.use(passport.session());
// initialize discord login
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((obj, done) => done(null, obj));
passport.use(new Strategy({
clientID: settings.config.clientID,
clientSecret: settings.config.secret,
callbackURL: settings.config.callback,
scope: ["identify", "guilds", "guilds.join"],
},
(accessToken, refreshToken, profile, done) => {
process.nextTick(()=>done(null, profile));
},
));
app.get("/login", (req, res, next) => {
if (req.session.backURL) {
// eslint-disable-next-line no-self-assign
req.session.backURL = req.session.backURL;
} else if (req.headers.referer) {
const parsed = url.parse(req.headers.referer);
if (parsed.hostname == app.locals.domain) {
req.session.backURL = parsed.path;
}
} else {
req.session.backURL = "/";
}
next();
}, passport.authenticate("discord", { prompt: null }));
app.get("/callback", passport.authenticate("discord", { failureRedirect: "/" }), async (req, res) => {
res.redirect("/dashboard");
});
app.get("/logout", (req, res, next) => {
req.session.destroy(() => {
req.logout(function(err) {
if (err) { return next(err); }
res.redirect("/");
});
});
});
const http = require('http').createServer(app);
http.listen(settings.config.port, () => {
logger.success(`Website is online on port ${settings.config.port}, ${settings.website.domain}`);
});
};
EDIT:
I found two ways that end the session:
app.get("/logout", (req, res, next) => {
req.logout(function(err) {
if (err) { return next(err); }
res.redirect("/");
});
});
app.get("/logout", (req, res, next) => {
req.session.destroy((err) => {
if (err) { return next(err); }
res.redirect("/");
});
});
CURRENT SCENARIO
Once I log in via social auth it shows the username and provider detail on the page. but if I refresh again it shows the error. I am sending the user object via render but still, it doesn't fetch the details. I don't understand why.
{"error":{"message":"Failed to fetch user profile"}}
Below is my express session snippet in my app.js file
app.use(expressSession({
name: 'Session',
maxAge: 24 * 60 * 60 * 1000,
secret: [keys.session.cookieKey],
resave: true,
saveUninitialized: true
}))
app.use(passport.initialize())
app.use(passport.session())
Below is my oauth.js file
const express = require('express');
const router = express.Router();
const passport = require('passport')
router.get('/login',(req, res, next) => {
//create a func where we check if the user logged in then show the profile page , if not logged in then show login page
res.render('login')
});
router.get('/logout', (req, res, next) => {
req.session = null
req.logout()
res.redirect('/')
});
router.get('/google', passport.authenticate('google', {
scope: ['profile']
}));
router.get('/facebook', passport.authenticate('facebook', {
scope: ['profile']
}));
router.get('/twitter', passport.authenticate('twitter', {
scope: ['profile']
}));
router.get('/github', passport.authenticate('github', {
scope: ['profile']
}));
router.get('/google/redirect', passport.authenticate('google', {
failureRedirect: '/login'
}), (req, res, next) => {
res.render('profile', {
user: req.user
})
});
router.get('/facebook/redirect', passport.authenticate('facebook', {
failureRedirect: '/login'
}), (req, res, next) => {
res.render('profile', {
user: req.user
})
});
router.get('/twitter/redirect', passport.authenticate('twitter', {
failureRedirect: '/login'
}), (req, res, next) => {
res.render('profile', {
user: req.user
})
});
router.get('/github/redirect', passport.authenticate('github', {
failureRedirect: '/login'
}), (req, res, next) => {
console.log('user details: '+req.user)
res.render('profile', {
user: req.user
})
});
module.exports = router;
When I have all of my code in app.js, authenticating with Google works fine, but I tried breaking out the authentication routes in their own files and now I get a connection refused.
//authRouter.js
const express = require("express");
const authRouter = express.Router();
const SECRETS = require("../config/secrets");
const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy;
const passport = require("passport");
passport.use(new GoogleStrategy(SECRETS.google,
(accessToken, refreshToken, profile, done) => {
return done(null, profile);
})
);
authRouter.get("/google", passport.authenticate('google', { scope: ['openid email profile'] }));
authRouter.get("/google/callback",
passport.authenticate("google",
{
failureRedirect: "/login",
successRedirect: "/"
},
(req, res) => {
res.render("hello world"); //successful auth, redirect home, but res is undefined
})
)
module.exports = authRouter;
//app.js
var authConfig = require('./config/secrets'),
express = require('express'),
passport = require('passport'),
TwitterStrategy = require("passport-google-oauth").OAuth2Strategy,
SECRETS = require("./config/secrets"),
authRoutes = require("./routes/authRoutes");
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((obj, done) => {
done(null, obj);
});
//setup for previously working Google auth
// passport.use(new GoogleStrategy(
// authConfig.google,
// (accessToken, refreshToken, profile, done) => {
// return done(null, profile);
// }
// ));
var app = express();
app.set('view engine', 'hbs');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
app.use(logger('dev'));
app.use(cookieParser());
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(__dirname + '/public'));
// Application routes
app.get('/', (req, res) => {
res.render('index', {
user: req.user
});
});
app.get('/login', (req, res) => {
res.render('login', {
user: req.user
});
});
//previously working google auth
// app.get('/auth/google',
// passport.authenticate('google', { scope: ['openid email profile'] }));
// app.get('/auth/google/callback',
// passport.authenticate('google', {
// failureRedirect: '/login'
// }),
// (req, res) => {
// // Authenticated successfully
// res.redirect('/');
// });
//**registering authentication routes
app.use("/auth", authRoutes);
app.get('/account', ensureAuthenticated, (req, res) => {
res.render('account', {
user: req.user
});
});
app.get('/logout', (req, res) => {
req.logout();
res.redirect('/');
});
app.listen(process.env.PORT || 3000, () => {
console.log("Listening...");
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
}
When I visit the app in a browser where I am logged i to Google, I get a connection refused. I know the credentials are correct, and it's likely some express setup I'm missing. Any thoughts? Thanks in advance.
I'm trying to add user-login module to an existing app in node. It is using separate route files for each module and one main route file to use all the child routes which is ultimately used in server.js
When I try to pass passport instance to the user route, it gives me error as passport is not defined. Here is my app code and structure:
app
views
user
index.ejs
login.ejs
signup.ejs
profile.ejs
routes
docs
index.js
user
index.js
index.js
config
passport.js
server.js
server.js
const express = require('express')
const app = express()
const path = require('path')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const passport = require('passport')
const flash = require('connect-flash')
const session = require('express-session')
const routes = require('./routes/')
const port = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'public')));
require('./config/passport')(passport);
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
app.use(bodyParser.json());
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(session({ secret: '********' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use('/', routes)(app,passport);
const server = app.listen(port, function(){
console.log('Server listening on port '+port);
});
config/passport.js
var LocalStrategy = require('passport-local').Strategy;
const sql = require('mssql')
const bcrypt = require('bcrypt-nodejs')
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function (username, done) {
done(null,username);
});
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
process.nextTick(function() {
var strSQL = "SELECT count(id) as uCount FROM <tbl> WHERE username = '"+email+"'";
var cb1 = function(err,recordset){
if(recordset[0].uCount>0){
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else{
var strSQL1 = "INSERT INTO <tbl>(username, password) VALUES('"+email+"','"+generateHash(password)+"')";
var cb2 = function(err,recordset){
return done(null, recordset,req.flash('signupMessage', 'Email registered successfully.'));
};
executeQuery(strSQL1,'INSERTION','<tbl>',cb2);
}
};
executeSelection(strSQL,'SELECTION','<tbl>',cb1);
});
}));
passport.use('local-login', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
var strSQL = "SELECT a.count, id, username, password FROM <tbl> c , (SELECT COUNT(dbid) count FROM <tbl> b WHERE b.username = '"+email+"' ) a WHERE c.username = '"+email+"'";
var cb1 = function(err,recordset){
if(recordset[0].uCount <= 0){
return done(null, false, req.flash('loginMessage', 'No user found.'));
}
if (!validPassword(password,recordset[0].password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
return done(null, recordset[0]);
};
executeSelection(strSQL,'SELECTION','<tbl>',cb1);
}));
};
executeSelection = function(strSQL, operationType, tableName, cb){
var request = new sql.Request(connection);
request.query(strSQL,function(err,recordset) {
if(err){
logger.error('ERROR in '+operationType+' ON '+tableName+': '+err);
}
logger.info(operationType+' ON '+tableName+' successful!');
cb(err,recordset);
});
};
executeQuery = function(strSQL, operationType, tableName, cb,validateClient) {
var request = new sql.Request(connection);
request.query(strSQL,function(err, recordset) {
if(err){
logger.error('ERROR in '+operationType+' ON '+tableName+': '+err);
}
logger.info(operationType+' ON '+tableName+' successful!');
if(cb){
cb(validateClient);
}
});
};
generatePasswordHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
validatePassword = function(curPass, dbPass) {
return bcrypt.compareSync(curPass, dbPass);
};
routes/index.js
const mainroute = require('express').Router()
/* ---- other existing routes included ---- */
const r_docs = require('./docs')
const r_user = require('./user') /*my custom route*/
/* ---- all other routes ---- */
mainroute.use('/docs', r_docs);
mainroute.use('/user', r_user)(app, passport); /*my custom route*/
mainroute.get('/', function(req, res){
res.render('home');
});
module.exports = function(app, passport){
mainroute;
}
routes/user/index.js
const express = require('express')
const router = express.Router()
router.get('/', function(req, res) {
res.render('user/index.ejs');
});
router.get('/login', function(req, res) {
res.render('user/login.ejs', { message: req.flash('loginMessage') });
});
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
router.get('/signup', function(req, res) {
res.render('user/signup.ejs', { message: req.flash('signupMessage') });
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile',
failureRedirect : '/signup',
failureFlash : true
}));
router.get('/profile', isLoggedIn, function(req, res) {
res.render('user/profile.ejs', {
user : req.user
});
});
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
module.exports = function(app, passport) {
router;
}
Please suggest what am I doing wrong here. Thanks
You should wrap your main and user routes to run their logic when you call them and at end return prepared route:
routes/index.js
module.exports = function(app, passport) {
const mainroute = require('express').Router()
/* ---- other existing routes included ---- */
const r_docs = require('./docs');
const r_user = require('./user'); /*my custom route*/
/* ---- all other routes ---- */
mainroute.use('/docs', r_docs);
mainroute.use('/user', r_user)(app, passport); /*my custom route*/
mainroute.get('/', function(req, res) {
res.render('home');
});
return mainroute;
};
routes/user/index.js
module.exports = function(app, passport) {
const express = require('express');
const router = express.Router();
router.get('/', function(req, res) {
res.render('user/index.ejs');
});
router.get('/login', function(req, res) {
res.render('user/login.ejs', {
message: req.flash('loginMessage')
});
});
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true
}));
router.get('/signup', function(req, res) {
res.render('user/signup.ejs', {
message: req.flash('signupMessage')
});
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
router.get('/profile', isLoggedIn, function(req, res) {
res.render('user/profile.ejs', {
user: req.user
});
});
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
return router;
};
You need to require it at the top of your user/index.js. Simply:
var passport = require('passport');
Then to make sure the user is authenticated:
router.get('/some/path', isLoggedIn, function(req, res) {
var user = req.user;
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
I am using this Express Server to authenticate users by signing in by their steam account.
everything works now as expected.
What i want to know now, is how i can integrate this to my Angular2 Project, so i can use in the HomeComponent a Login Button which calls the Express Server.
Is it better to work with an Server.js or with a Server.ts Backend Server?
and will it be visible ? if yes, where should be its destination to garantuee security ?
Im new to this, thats why im so curious :)
thanks in advance
const express = require('express');
const session = require('express-session');
const FirebaseStore = require('connect-session-firebase')(session);
const firebase = require('firebase-admin');
const firebaseinit = firebase.initializeApp({
credential: ('**************************************'),
databaseURL: '**************************************'
});
// *************************************************************************************************************
var passport = require('passport'),
util = require('util'),
SteamStrategy = require('./').Strategy;
// *************************************************************************************************************
passport.serializeUser(function(user, done) {
done(null, user);
});
// *************************************************************************************************************
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
// *************************************************************************************************************
passport.use(new SteamStrategy({
returnURL: 'http://localhost:3000/auth/steam/return',
realm: 'http://localhost:3000/',
apiKey: '**************************************'
},
function(identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
));
// *************************************************************************************************************
var app = express();
app.set('views', __dirname + '/signon/views');
app.set('view engine', 'ejs');
app.use(session({
store: new FirebaseStore({
database: firebaseinit.database()
}),
secret: 'keyboard cat',
name: 'name of session id',
resave: true,
saveUninitialized: true
}));
// *************************************************************************************************************
// *************************************************************************************************************
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(__dirname + '/../../public'));
// app.post('/auth/openid', passport.authenticate('openid'));
// *************************************************************************************************************
app.get('/auth/steam',
passport.authenticate('steam', { failureRedirect: '/' }),
function(req, res) {
res.redirect('/');
});
// *************************************************************************************************************
app.get('/auth/steam/return',
passport.authenticate('steam', { failureRedirect: '/' }),
function(req, res) {
res.redirect('/');
var db = firebase.database();
var ref = db.ref("/UserID");
var SteamUserID = ref.child(req.user.id);
SteamUserID.update({
Username : req.user.displayName,
UserImg : req.user.photos[2].value
});
});
// *************************************************************************************************************
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
// *************************************************************************************************************
app.get('/', function(req, res){
res.render('index', { user: req.user });
});
// *************************************************************************************************************
app.get('/account', ensureAuthenticated, function(req, res){
res.render('account', { user: req.user });
});
// *************************************************************************************************************
app.listen(3000, function () {
console.log('listening on port 3000!')
})
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/');
}
console.log('Listening on port ' + app.listen);