Why request user is undefined in Sapper App - node.js

I cannot set a req.user in my Sapper app, what am I doing wrong
express()
.use(
bodyParser.urlencoded({
extended: true
}),
bodyParser.json(),
compression({
threshold: 0
}),
sirv('static', {
dev
}),
cookieParser(),
session({
store: store,
secret: 'somesecret',
resave: false,
saveUninitialized: true,
cookie: {
secure: true,
maxAge: 604800000,
}
}),
passport.initialize(),
passport.session(),
sapper.middleware({
session: (req, res) => {
let user = req.session.user
return {
user
}
}
}),
)
i have a login component from which im using fetching
in login folder i have a login.js file a server side route and i cannot get my req.user not req.session.user , not req.session.passport

I had the same problem.
I installed the module "express-session". (This module works with polka.js too)
And set the sapper's middleware:
sapper.middleware({
session: (req, res) => ({
user: req.session.user
})
I wrote a 'api/login/' to the sever side and a login page.
Once the server recognize the user with his login and pass', I use a goto(".").
The goto()'s behavior should be like a location.href. But this is not.
So I replace goto(".") by location.href("."). With this, I have the session's data from the server.(in the preload and with the stores => $session.user).
I hope that can help you.

I have found partial solution, please correct this if Iam wrong. So entire app is controlled over sapper.middleware and server it self has no automatic effect on it.
So no req.user is set, no session and no cookie value is set, every thing must be manually set from authentication route.
So my solution was to set cookie in login post route, so in login.js file.
import passport from 'passport'
export async function post(req, res, next) {
passport.authenticate('local', (err, user, info) => {
if (err) {
return res.json(err)
}
if (user) {
// console.log(req)
return res.status(201).cookie('user', req.sessionID).json({
email: user.email,
id: user._id
})
}
if (info) {
return res.json(info)
}
})(req, res, next);
}
in login.svelte component i set my session (SAPPER MIDDLEWARE SESSION)
session.set({ user: true, email: user_data.email, id: user_data.id });
So my Further action is to check if sessionid exist in session store on server if yes continue if no set user to null and redirect to login.
is it correct ? Is it safe enough ?
Edit
So My partial "solution" is not right for any one having the same problem with passport authentication solution is
you must define route in server.js prior sapper.middleware
app.httpRequest('/route',YOURAUTHENTICATION MIDDLEWARE)
in your route.js file or in route folder index.js file you will have your req.user
in sapper middleware your session object must look like this
session: (req, res) => ({
user: req.session.passport ? req.session.passport.user : null })
if you will try to pass req.user it will not be serialized by sapper / devalue package and you will keep getting error.
After this in your route.js you can preload user from session. hope this was clear !

Related

req.isAuthenticated() always returns false outside of passport local strategy

When I call req.isAuthenticated() in my local login strategy upon successful login, it always returns true as it should. However, when I try to call req.isAuthenticated in any other file/route in my express server, it always returns false, even when I have a successful login cookie and session. Does anyone have any idea as to why this is? If not, does anyone have any good open source alternatives to passport.js for auth?
Relevant code from express server:
app.use(session({
secret: process.env.AUTH_SECRET,
resave: false,
saveUninitialized:false,
cookie: {
secure: false,
expires: cookieExpirationDate
}
})); // session secret
app.use(passport.initialize());
app.use(passport.session());
...
app.get('/logincheck', (req, res) =>{ //route called by front end component to check auth status
if(req.isAuthenticated()){ //returns false even with cookie and session in browser
res.json({isAuth: true})
}
else res.json({isAuth: false})
})
Relevant code from local login strategy:
var userinfo = user.get();
req.login(user, function(error) {
if (error) return next(error);
console.log('success!')
})
console.log(req.isAuthenticated()) //always returns true on successful login
return done(null, userinfo);
I've tried all of the relevant solutions discussed in this issue:
passport's req.isAuthenticated always returning false, even when I hardcode done(null, true) so any help is greatly appreciated as I feel like I have been getting nowhere with this problem.

passport google : why sessionID is different in the callback?

Dears,
there are a lot of examples around passport google, but there should be something I missed. I know my question might be marked as "possible duplicate", but sorry I can't find the answer, or none of them are fixing my issue.
the user clicks a href link on the client (running on https://localhost:3000), calling the googleauth route on the server (running on https://localhost).
On server side, passport process is running well, the callbackUrl is on the server side at /googleauth/redirect.
Then in this callback, I can hardcoded the redirect to 'https://localhost:3000'. that works fine.
But I don't want this. I want the server to catch the initial url from the client (so https://localhost:3000), keep it in the session and then use this information in the redirect.
In the google auth route, I set the toRedirect variable into the session thanks a middleware, before calling the passport.authenticate.
googleRouter.get('/', (req, res, next) => {
if (!req.session.toRedirect) req.session.toRedirect = req.socket.remoteAddress;
next();
}, Auth.passport.authenticate('google', {
scope: ['profile', 'email', 'https://mail.google.com/'],
accessType: 'offline',
prompt: 'consent',
session: false // <-- whatever true or false, same issue
})
);
However once the google process is complete (choose the google account and confirm the acces to user data), the sessionID is different in the callback, therefore the url to redirect is undefined... And of course the remote address is no longer the client one, but the google authentification APIs one...
googleRouter.get('/redirect', Auth.passport.authenticate('google', { session: false }), (req, res) => {
console.log(req.session.toRedirect, req.sessionID, req.socket.remoteAddress) // <--- sessionID is different so req.session.toRedirect is undefined
res.redirect('https://localhost:3000'); /<--- hardocded here but I want res.redirect(req.session.toRedirect).
});
So guys, how did you send back the google auth results to your clients ?
Here is the code
apps.js
const passport = Auth.passport;
app.use(passport.initialize());
app.use(passport.session()); <-- whatever set or not, same issue
auth.js
const googleOptions = {
clientID: sds,
clientSecret: dsadd,
callbackURL: '/googleauth/redirect',
passReqToCallback: true
};
passport.use(new GoogleStrategy(googleOptions,
async (req, token, refreshToken, profile, done) => {
data = await Auth.helpers.signIn(req, null, 'google');
if (data && data.erreur == authErrors.NONE) {
// MAJ de la session et cookie
req.session.userId = data.user.id;
done(null, data.user);
};
));
googleroutes
googleRouter.get('/', (req, res, next) => {
if (!req.session.toRedirect) req.session.toRedirect = req.socket.remoteAddress;
next();
}, Auth.passport.authenticate('google', {
scope: ['profile', 'email', 'https://mail.google.com/'],
accessType: 'offline',
prompt: 'consent',
session: false
})
);
// callback route pour redirect google
googleRouter.get('/redirect', Auth.passport.authenticate('google', { session: false }), (req, res) => {
console.log(req.session.toRedirect, req.sessionID, req.socket.remoteAddress)
res.redirect('https://localhost:3000');
});

Using a cookie to determine if a user needs to log in again, Node.js and Express

I've a login page (using a HTML form) that when a user enters a password (pre-determined) they can view a site. What I would like is, when the user is logged in, a cookie timer will start and last for 24 hours, when 24 hours expires, they will have to log back in when they view the site. I've done a fair bit of research into this but am struggling a small bit to understand due to my lack of experience with Node.js. I appreciate that using a pre-determined password is poor practice but for what I'm doing, it suits.
Below is the code I have in the server.js file. I had a normal login working prior to starting with cookies so it's just the cookie part I'm having trouble with. Obviously the code below is missing something like MaxAge but I dunno where to implement it.
Thanks
function checkAuth(req, res, next) {
if (!req.session.user_id) {
res.send('You are not authorized to view this page');
} else {
next();
}
}
app.get('/home', checkAuth, function (req, res) {
res.send('if you are viewing this page it means you are logged in');
});
app.post('/login', function (req, res) {
var post = req.body;
if (req.body.name == "login"){
req.session.user_id = "login";
res.redirect('/home');
} else {
res.send('Bad user/pass');
}
});
When you initialise your session, add the maxAge to the cookie.
app.use(session({
secret: 'your secret key',
resave: true,
saveUninitialized: false,
cookie: {
secure: false,
maxAge: 1440000
}
}));
This sets the maxAge of all the cookie. Post which you can check if the request is authenticated.

How to give session only if authenticated? Any other middleware order won't work

I have this issue where a session is created regardless if the user is logged in or not.
I would like it if a session is created only if the user logs in successfully. Otherwise, if a selenium bot hits...for example, the route route('/users/:username') my session collection would fill up with sessions that are not from real users. I am having my users stay logged in forever, so the session cookie is set to a year...which is even worse if the session does not belong to real user.
How can I have a session returned to the client only if the authenticate successfully? I tried different order of the routes and middle ware, but this is the only order that works correctly.
app.use(session({
secret: 'bob',
saveUninitialized: true,
resave: true,
name: 'curves',
cookie: { secure: false, httpOnly: false,
maxAge: 365 * 24 * 60 * 60 * 1000 },
store: new MongoStore(storeOptions)
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', auth);
app.use('/api/v1', router);
// isLoggedIn WOULD NOT WORK IF I PLACED THIS BEFORE PASSPORT/SESSION MIDDLEWARE
router.route('/users/:username')
.get(isLoggedIn, api.getUsername);
auth.route('/auth/facebook')
.get(passport.authenticate('facebook', { scope : 'email' }));
auth.route('/auth/facebook/callback')
.get(function(req, res, next) {
passport.authenticate('facebook', function(err, userDoc, info) {
if (err) { return next(err); }
// I don't think !userDoc will ever happen because of mongo upsert
if (!userDoc) { return res.redirect('/login'); }
req.logIn(userDoc, function(err) {
if (err) { return next(err); }
return res.redirect('http://localhost:9000/users');
});
})(req, res, next);
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.status(404).json({ error: "not logged in" });
}
Figured it out...I just needed to set saveUninitialized: false.
saveUninitialized
Forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified. Choosing false is useful for implementing login sessions, reducing server storage usage, or complying with laws that require permission before setting a cookie. Choosing false will also help with race conditions where a client makes multiple parallel requests without a session.
The default value is true, but using the default has been deprecated, as the default will change in the future. Please research into this setting and choose what is appropriate to your use-case.
Note if you are using Session in conjunction with PassportJS, Passport will add an empty Passport object to the session for use after a user is authenticated, which will be treated as a modification to the session, causing it to be saved.

Node: How do I store data in an express session, so that I can access it from socket.io?

So, for learning purposes, I am writing a chat application with Node and Express. I use MongoDB/Mongoose, Passport for authentification, and socket.io for the actual chat part of the app.
I have a working registration/login/logout system. My problem is in the socket.io code. When I emit a message from a client, I want to know in the sever-side code, from what user the message originated. So, in PHP for example, I would save the user name in a session variable upon login, and later use it from somehwere else. So I attempted to do something similar here:
router.post('/',
passport.authenticate('local',{ failureRedirect: '/login', failureFlash: true }),
function(req, res) {
User.findOneAndUpdate({_id: req.user._id}, { lastConnection: new Date() }, {} ,function (err, user) {
req.flash('welcomeMessage', 'Welcome ' + user.name + '!');
req.session.user=user.name; //Here I try saving the user name
req.session.cookie.user=user.name; //Same here, for testing purposes
res.redirect('/');
});
});
But how do I access this data from within socket.io? In another Stackoverflow question, someone provided the following code for exposing the express session to socket.io:
io.use(function(socket, next) {
var req = socket.handshake;
var res = {};
cookieParser(req, res, function(err) {
if (err) return next(err);
session(req, res, next);
});
});
This permits me to access the session:
io.sockets.on('connection', function (socket) {
//Express session:
console.log("Session: ", socket.handshake.session);
Which gives me this output:
Session: {cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true
}
}
This does not contain the added data. My guess is, this is the session at the point where my application starts, before I did performed a login, and therefore before any data was added to the session.
Unfortunately, I'm at a loss on how to proceed. I'm grateful for any suggestion :)
In your Session Initialisation change default httpOnly: false settings to true.
Since, it is strict httpOnly it is denying AJAX request.
In your app.js or server.js where you're initialising Session do something like this.
var session = expressSession({
secret: 'secret key',
key: 'express.sid',
resave: false,
saveUninitialized: true,
cookie: {httpOnly: false}
});
Note: cookie: { httpOnly: false } is important, rest code is for example.
Thanks.

Resources