node sessions not clearing in production - node.js

I am using client-sessions with node and express, and I am having trouble logging out users.
my logout function does a
req.session.user=null
that is:
userRouter.get('/logout', function(req, res, next) {
req.session.user = null
res.sendStatus(200)
});
(I also tried delete req.user, req.user.destroy(), and other variants).
in dev env, on localhost, it works great.
in production environment, logout is called, but the next time the user refreshes the page on the browser, the user is still logged in.
same code in dev and production.
Anybody has any idea?
thanks....

According to this blog post on client-sessions, you can use this:
userRouter.get('/logout', function(req, res, next) {
req.session.reset();
res.sendStatus(200);
});

so it the end the issue was that I did not have
headers: {
'Accept': 'application/json',
},
in the call from the client. I a bit puzzled by this, it seems as the server would set the session (through nginx) only if the client had this header, while in localhost it sets sessions correctly without this.

Related

Passport-auth0 - infinite redirect loop, "Invalid authorization request state."

I'm trying to get a basic Auth0 app running. I followed the Node example on the Auth0 dashboard but I ran into an infinite redirect loop between /login and /callback. I tried to simplify the code using the getting started example of this repo's readme, right now my routing code looks like this:
app.get('/login',
passport.authenticate('auth0', {scope: 'openid email profile'}),
(req, res) => res.redirect("/")
)
app.get("/callback",
passport.authenticate('auth0', {failureRedirect: '/login'}),
(req, res) => {
if(!req.user) throw new Error("user null")
res.redirect("/")
}
)
Everything about my setup follows the instructions I got on my Auth0 dashboard.
I did some digging and found out that /login is called twice, then /callback is called twice, then /login twice and so on and so on. I also found out that if I give the /callback's passport.authenticate a callback, it receives these arguments: null, false, {message: "Invalid authorization request state."}
Google didn't find anything meaningful when I searched for the phrase "Invalid authorization request state." and I did everything according to the docs. Any idea what I'm doing wrong?
I have had the same issue with these error and was caused due to session loss on Kubernetes landing my calls to different instances each time (sort of like load balancing), what we did was to lower from 3 instances to 1 and that fixed it. Also you could set in your Auth0Strategy config the value of state: false to double check if this lets you move on.
It turns out I didn't have the /callback route set up properly. This is the proper setup:
router.get("/callback", (req, res, next) => {
passport.authenticate('auth0', (err, user, info) => {
if(err) return next(err)
if(!user) return res.redirect("/failure?info=" + JSON.stringify(info))
req.logIn(user, err => {
if(err) return next(err)
const returnTo = req.session.returnTo
delete req.session.returnTo
res.redirect(returnTo || '/secret')
})
})(req, res, next)
})
res.redirect should lead somewhere else and req.logIn needs to be called with the proper arguments
For those who are still having issues, the problem might lie elsewhere. When I ran into this it turned out to be caused by session cookies that weren't persisting! It turned out my reverse proxy (running on Apache) wasn't configured properly. I've described my solution here: https://stackoverflow.com/a/67891167/8221175
As for why this might happen for those interested, I've posted an explanation on one of the GitHub issues here: https://github.com/auth0/passport-auth0/issues/89#issuecomment-856971807
In short: The state query parameter in the response of a login call is saved in the session. If sessions don't persist, passport can't get that state data and it'll think someone is hijacking your session. That causes the “Invalid authorization request state.” message, as well as the user to be falsy in the passport.authenticate callback. If your code then redirects to '/login', the whole thing repeats, causing an infinite loop.
The fix is to make sure your cookies are saved properly and your sessions therefore persist. You can use the examples I've provided in the links.

Passport.js Azure AD auth always fails the second time

So i'm using Passport.js in Express to authenticate users in an app with the passport-azure-oauth2 strategy.
The first login works fine, the Microsoft portal takes me back to /cb which is
app.get("/cb", auth.passport.authenticate("provider", {
successRedirect: "/",
failureRedirect: "/login"
}), function (req, res) {
res.redirect("/");
});
And it successfully redirects me to '/'. At this point I can log out 'Logged in' via this
if(req.isAuthenticated()) {
console.log('Logged in');
} else {
console.log('Not logged in');
}
The issue comes when I either log out and try and log back in again, or try and log in with a different browser. The Microsoft portal always takes me back to '/login', leaving me in a loop.
The login script is simply:
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
On Chrome, when I log in (even successfully) it logs an error:
Set-Cookie header is ignored in response from url: https://login.microsoftonline.com/common/login. Cookie length should be less than or equal to 4096 characters.
I'm guessing the issue might be something to do with this? But i've tried everything I can think of to no avail.
it's been a while since you have asked this, but maybe it could be helpful for someone else.
After a day of debugging i found out that the service worker of my react app was messing with the passport authentication strategy.
As you have described, when you load the page for the first time the service worker is not registered yet, but when you get redirected to the homepage the script in the index.jsx enable the worker in the browser (i used it to display the install app button on chrome), so if you logout and try to login again this issue comes along.
If you are in a rush i suggest you to temporary disable the worker if it's not very important for the right functioning of your app and you'll see that everything works fine.
It works on localhost because the script detects your environment and it does not start.
Unfortunately i have not found a permanent solution yet.

How to use authenticated middleware properly in nodejs

I just started working on node using express framework.
app.use('/', auth, users);
and this is my route file
router.get('/' , function(req, res, next) {
render("dashboard");
});
router.get('/first' , function(req, res, next) {
//first request
});
router.get('/second' , function(req, res, next) {
//second request
});
so on...
My question is, when i pass middleware it checks for every request whether its authenticated or not using passportjs, but suppose i have a dashboard and i am sending 10 ajax requests to grab data for the widgets. So only for dashboard it will call deserialize function 11 times ,first to render the page and then for 10 ajax request. I read answer given over here,
How to properly use Passport.js?
But is it fine to go with this approach?
Yes, it is fine to go with this approach if you don't want to have security issues. You have to check the user for every request, it is very simple someone to check the network tab in the browser debugger, understand what's going on and then start spoofing your requests. You can't sacrifice security for performance because you want to execute few query less.

Node Express - res.redirect() not behaving as expected

I am trying to redirect to a login page after successfully logging a user out, but am having an issue when calling res.redirect() from my logout route handler in express.
I have the following middleware to redirect a user to a login page (note I am using express-session too)
//A request to '/login' will serve the login page
app.use('/login', function(req, res){
res.sendFile(path.join(__dirname+'/public/login.html'))
});
//This will listen for all requests
app.use(function(req, res, next) {
//Here we only want to redirect to the logic route (above) if the request is not
//a login action and there is no access token present on the session object
if (req.url!== '/auth/login' && !req.session.accessToken) {
res.redirect('/login');
} else {
next();
}
});
This redirect above works as expected.
When a user performs a logout, I handle like so:
app.post('/auth/logout', function(req, res){
req.session.destroy();
res.redirect('/login');
});
I can see in Chrome debugger, the network tab shows my login view is being served back to the browser, but the browser window does not change. I notice the login.html is being returned with a 304 code too if that has any relevance. I'm feeling a bit dumb but am failing to see what's different here, can someone shed some light please?
Thanks

Logging out with Firebase and Node.JS

I wanted to provide a Node.JS Express route wrapper for users who needed to logout and didn't have JavaScript enabled on the front-end. DB is my reference to my Firebase:
router.get('/logout', function(req, res) {
DB.unauth();
res.redirect(302, '/');
});
When I try to logout this way having been logged in, I get the following error:
Error: Can't set headers after they are sent.
The documentation for Firebase.unauth() is pretty light, but calling it in a route (with or without the res.redirect) causes the error. Does anyone have a suggestion or workaround for this issue?
So i was running into the same problem. For me it was that i was using the asynchronous authDataCallback function.
Apparently onAuth sets your headers so when you try to go to /logout your headers are set and the redirect will fail. So what i did is i switch the authDataCallback
that i had checking for login states to:
var authData = ref.getAuth();
if (authData) {
console.log("User " + authData.uid + " is logged in with " + + authData.provider);
} else {
console.log("User is logged out");
}
then my route for log out work flawlessly.
app.get('/logout', function(req , res){
ref.unauth();
res.redirect('/');
});
Looks like that error is being thrown on the redirect - you can't headers once the body has been sent. Maybe try:
response.writeHead(302, { Location: '/' });
response.end();
If that doesn't work, I'd put money on that .unauth() is actually setting headers, and if it is, you'll probably need to use the ol' <noscript> tag.
All of this said though: you're building an app that uses JavaScript to integrate with Firebase on the back end. Why build a modern web-app that (presumably) relies heavily on JavaScript only to support logging out users when they don't support it? Could they even log in in the first place?

Resources