using csurf with session in express - node.js

I'm writing a single page application with MEAN stack, and using express-session with redis for session management.
I want to use scrf token in my client's cookies.
the problem is when I add csurf middleware, it set a session with name csrfSecret in redis, but how can I send it in cookie to client?
middlewares :
app.use(csrf({}));
app.use(function(req, res, next) {
res.cookie('csrf-token', req.csrfToken());
return next();
});
and csrf-token is sending to client but it don't do anything.and I receive 403 error from module.
thank you for any answer or idea.

If you want to create a csrf cookie in the client you have to use the following:
app.use(csrf({ cookie: true })
This will create a token in the client. If you do not pass any options to the csrf function it will use req.session. If you want to save the cookie client-side, remember that you will need to use cookie-parser module.
You can find more information in the github link to the project: https://github.com/expressjs/csurf

Related

passport-local cookie and session database handling

I am currently trying to setup an oauth service for my current project. Being new to all this, I have read many articles on the subject, but I am still missing some pieces.
My environment is:
servers: node, express, passport
authentication: local strategy (using my own accounts / passwords)
I have a database with user/password ( passwords run through bcrypt)
web interface: react, server accesses through superagent
On my nodejs server, I am using these modules:
express
express-session
express-mysql-session
passport
passport-local
bcrypt
Different parts of the solutions are working: I can create new users, create new sessions, see their content in the express-mysql-session database.
However I am quite confused on the following:
when my web client tries to access protected routes, I don't seem to be getting any cookie in the request. Is it that superagent will not send my passport cookie by default? I read somewhere that in single page apps, jwt might be more appropriate, is that linked to this problem?
despite all I read, I am still confused about deserializeUser. My understanding is that with the passport-local solution, upon access, the web client will send the session cookie, which contains the session Id. Passport will fetch further information concerning this session from database, and then continue to handle the request. Does this session info retrieval happen automatically (in express-mysql-session?)? Or do you have to "manually" do it in deserializeUser (many examples show a User.findById call in there)? If you have to do it "manually", it means that you have to access the express-mysql-session db using another connection than the one this module is using?
to log out, is req.logout() enough to ensure the session is erased from the session db entirely?
Answers I found so far:
One has to add the withCredential method to superagent, to get it to send authentication cookies:
res = await superagent
.get(url)
.withCredentials()
.send();
On the CORS side of things, on the server, the 'credentials' option is required if using the 'cors' npm module, for instance:
app.use(cors({
origin: ['http://localhost:3003'],
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
credentials: true,
}));
All session information is automatically retrieved by these modules. However, many example show this call going back to the user database to get more information (rights, other info). The goal is to avoid having the same information in two locations (sessions db, and user profiles db), and having these getting out of sync (when an account gets closed etc...)
req.logout() disconnects the session, but the session information sticks around in the database.
The following question put me on the right track: how to delete cookie on logout in express + passport js?. You need to use req.logout, res.session.destroy, and while you're at it res.clearCookie to delete the client cookie:
router.post('/logout/',
(req, res) => {
req.logout();
res.status(200).clearCookie('connect.sid', {
path: '/',
secure: false,
httpOnly: false,
domain: 'place.your.domain.name.here.com',
sameSite: true,
}).end();
req.session.destroy();
},
Session is disconnected, database cleaned, cookie gone.

Express req.session is set and then empty when trying to POST

I have a MERN stack blog app that I'm making as a learning exercise. I'm relatively comfortable on the front end but have limited experience in node. I'm adding authentification after following a couple tutorials to get this far. I'm using passport.js as a framework to make a request to Google, get back an id and save as session info. However, after logging in, req.session is empty when making a post request, even though I can see a cookie in the dev tools.
I'm using bcrypt's hash to obscure the actual id, but that may not be best practice.
in blogAuth.js: req.session is defined.
bcrypt.hash(req.user._id.toString(), saltRounds, function(err, hash) {
req.session.user = hash;
//session is set here.
console.log(req.session); res.redirect(http://localhost:8080/articles/loggedIn);
});
but in api/articles.js: req.session is empty
router.post("/", (req, res, next) => {
const { body } = req;
// session is empty here. Why?
console.log(Session user, ${req.session.user});
console.log(req.session);
I have tried:
Including proxy in the client package.json:
express req.session empty with cookie-session
using withCredentials set to true when sending the POST from the
client:Node + Express + Passport: req.user Undefined
Rearranging the order of middleware: Routes must always come
afterward, but I feel like I'm doing this blindly and it usually results in an error
Here's some of the relevant files:
Server side:
- app.js
- blogAuth.js
- passport.js
- api/articles.js
Client side:
- the POST req
Entire project
I believe this is an issue with ordering. What is a good way to ensure that I order my middleware correctly? Or if the order looks correct, where else could this issue becoming from?
You are trying to use cookie-session as well as express-session. Since both of them will try to control the fate of req.session object, you will end up with empty session always.
Just remove one of them, and your session will be persisted.

Authentication without Passport

I'm using active directory to authenticate users, so I thought I didn't need to use Passport and that all I would need to do is after the password checks out is to create a global(?) boolean with res.locals to indicate that the user has been authenticated.
I've tried something like this in a controller function:
ad.authenticate(username,password, function(err,auth) {
//some of the things I tried unsuccessfully -- should be true after logged in
res.locals.auth = auth
app.locals.auth = auth //app not defined
})
However, I've discovered that when I call a later function checking if the user is logged in as part of middleware for a diff route, res.locals.auth and app.locals.auth are either false or undefined. I've tried setting both vars in my server.js file at the beg with the code below but that didn't work either...
app.use((req, res, next) => {
app.locals.auth = false;
res.locals.auth = false;
next();
});
So my question is, what var/where should I be saving the authenticated status? Or should I just use passport instead because there's some security concern that I was unaware of? What is the point of the isMemberOf in passport setup example?
https://www.npmjs.com/package/passport-activedirectory
All I want to do is just check user credentials and basically recreate req.isAuthenticated in Passport because I couldn't figure out how to use it because of the isMemberOf.
Usually the server sends back a token containing some useful data (user or session id, expiration date) either by cookies or by JWT (json web token).
Then a client puts the token into every request to the server . The server validates expiration date and handles requests.
Cookies will be put into a request by the browser automatically. JWT should be put into a request by your client code.

Delete cookie from user browser after the session ends. Im using Passport-twitter to authenticate the user.

Hello i am building an app that is using passport-twitter to authenticate the user, im able to succesfully login the user using twitter credentials, but i would like for the user when we sign out (destroy the session), so the cookie is also destroy, so everytime the user comes back to the app, he needs to authenticate again. so im guessing my session has to be modified but i dont know how.
app.use(session({
secret: "our-passport-local-strategy-app",
resave: true,
saveUninitialized: true
}));
any help is appreciated
Try to use Passport's official approach for logging out. The request object has a decorator that it can be used. If you are using Express.js 4.x the 'result' object has cookie manipulating decorators as well.
app.get('/logout', function(req, res){
// Destroy the session if any
req.logout();
// Clear the specified cookies
res.clearCookie('your_key');
// Redirect to homepage
res.redirect('/');
});

CSRF token issues with Express

I am trying to get CSRF protection working using csurf and express. My app uses Angular for the front end, so I figured adding this to my app would be enough:
app.use(cookieParser('test secret'));
app.use(cookieSession({
secret: 'test secret'
}));
app.use(csrf({
cookie: {
key: 'XSRF-TOKEN'
}
}));
However, when I try to make POST requests, I get 403 ("invalid CSRF token") errors.
As far as I can tell, the issue resides in the csrf-tokens module: at line 44, the expected variable looks like qMnHLQGhivxECx5WtwuktDNA-snimacq30z-XNh2X-KTpdlkU6Og while the secret and token variables look like qMnHLQGhivxECx5WtwuktDNA. Since expected and token are different, a 403 error occurs.
I have, so far, tried the following:
Setting secure: false and/or signed: true in my csurf options
Making sure that my cookie-session and cookie-parser middleware run before csurf
Re-installing all my npm modules just in case
Yelling at my computer
I could, potentially, switch to session-based tokens, but that wouldn't work as smoothly with Angular, and I'm not sure if it would even solve my problem.
Does anyone know how to fix this issue, or what the cause might be?
P.S. By the way, I've also noticed a (probably unrelated) issue: the req.csrfToken() method seems to return strings whose values are entirely unrelated to the expected value in csrf-tokens or to the string being stored in the cookie.
There is an error/bad implementation regarding csurf lib. The cookie "XSRF-TOKEN" does not store the csrf Token, but the secret that csurf uses to generate the csrf token. Therefore, the Angular part of your app identifies the XSRF-TOKEN and appends the header correctly to HTTP requests, but the csurf middleware does not recognize the secret as a valid CSRF token itself. To fix this problem, you should implement this as:
var cookieParser = require('cookie-parser');
var cookieSession = require('cookie-session');
app.use(cookieParser("secret"));
app.use(cookieSession({secret: "secret2"}));
app.use(csrf());
app.use(function (req, res, next) {
res.cookie("XSRF-TOKEN",req.csrfToken());
return next();
});
The req.csrfToken() will generate the csrf token based on the secret stored, in this case, in the req.session.csrfSecret variable, generated by the csrf middleware. Then, it will work.
EDIT: See this issue on GitHub

Resources