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').
Related
I have scoured the community for answers, but I cant seem to find one.
In my application, I send user info from the client (react) to /user/save route. When I log the session to the console, all the data is there. But when I log req.session out on any other route it doesn't have any data.
Right now I am accessing the API from localHost while the API is hosted with ngrok.
When I had the API integrated within the same codebase as my React app, all worked well, but now it's a bit funky.
Server.js
const express = require('express');
var expressSession = require('express-session');
const cors = require('cors');
const cookieParser = require("cookie-parser");
const path = require('path');
const app = express();
const axios = require('axios');
const mongoose = require('mongoose');
const rateLimit = require("express-rate-limit");
var cron = require('node-cron');
require('dotenv').config()
const corsConfig = {
"origin": "http://localhost:3000",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"credentials": true
};
// Implemented a rate limiter which is a TEMPORARY FIX for the infinite loop by the useEffect
const limiter = rateLimit({
windowMs: .1 * 60 * 1000, // 10 seconds limit
max: 4
});
// Middleware
const hostValidationMiddleware = require('./Middleware/HostValidationMiddleware');
const sessionValidationMiddleware = require('./Middleware/SessionValidationMiddleware');
const {authenticateJWT} = require('./Middleware/JwtMiddleware');
async function connectToDB() {
// Database
await mongoose.connect(process.env.mongo_url, { useNewUrlParser: true, useUnifiedTopology: true }, () => {
console.log('[connectToDB]: Connected to DB');
})
}
connectToDB();
app.use(cookieParser());
const oneDay = 1000 * 60 * 60 * 24;
// Creating the session in order to save user data to req.session
app.use(
expressSession({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
secure: false,
cookie: {
maxAge: oneDay,
sameSite: "none",
}
})
);
app.use(cors(corsConfig));
//app.use('/', limiter);
app.use(express.json());
app.use('/', hostValidationMiddleware, sessionValidationMiddleware, require('./Routes/Store-Invoices'));
app.use('/', require('./Routes/SaveLoggedInUser') , authenticateJWT, require('./Routes/GetUserInvoices'));
app.use('/', require('./Routes/UpdateUserData'));
app.get('/', async (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(8081, () => {
console.log(`Server listening on 8081`);
});
Saved Logged In User
saveLoggedInUser.post('/user/save', async (req, res) => {
const User = req.body;
const token = await GetJwt(User);
req.session.currentUser = User;
if (token && !('authorization' in req.session) && User) {
req.session.authorization = `Bearer ${token}`
req.session.save();
}
console.log('USER', req.session);
const usersFromDB = await fetchUsersFromDB().catch((e) => { console.log(e) });
findCommonUser(usersFromDB,User);
res.sendStatus(200);
})
Get User Invoices
userInvoices.get('/invoice/user', async (req,res) => {
const invoices = await InvoiceModel.find().catch((e) => {console.log(e)});
const user = req.session;
console.log('INVOICE',user);
});
Client Call
async function fetchUserInvoices() {
// Making a call to external api
const url = `https://f604-104-49-198-21.ngrok.io/invoice/user`;
const invoiceResponse = await axios.get(url, {withCredentials: true}).catch((e) => { console.log(e) });
setData(invoiceResponse.data);
return;
}
It looks like you have your SameSite cookie flag set to "none" which according to MDN now requires the "Secure" flag to also be set to true in order to work. However, as you're using localhost, you probably also can't set Secure to true since you're not on HTTPS.
Removing that line in your Server.js code fixed it for me, as did setting sameSite: "strict".
let createError = require("http-errors");
let express = require("express");
let path = require("path");
let cookieParser = require("cookie-parser");
let logger = require("morgan");
const session = require("express-session");
let fileStore = require("session-file-store")(session);
const oneDay = 1000 * 60 * 60 * 24;
// Routers
let indexRouter = require("./routes/index");
let usersRouter = require("./routes/users");
let loginPage = require("./routes/login");
let app = express();
// System settings
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");
app.set("trust proxy", 1);
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
app.use(
session({
secret: "SECRET_KEY_FOR_SESSION",
saveUninitialized: true,
resave: false,
cookie: { maxAge: oneDay, secure: !true },
store: new fileStore(),
})
);
app.use("/", indexRouter);
app.use("/login", loginPage);
app.use("/users", usersRouter);
app.get("/createSession", (req, res, next) => {
res.send("This is sessionCreate file");
let mysession = req.session.save;
mysession.data = "LOGIN";
res.end;
});
app.get("/getSession", (req, res, next) => {
let getsession = req.session;
res.send(`${getsession.data}`);
res.end;
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render("error");
});
module.exports = app;
getsession.data === undefined?
I uploaded a variable to the session but it was not detected?
All system settings are set correctly but what is the error? Session => The session is being saved to a storage folder but cannot be read.
session_saved_folder
Specifies the boolean value for the Secure Set-Cookie attribute. When truthy, the Secure attribute is set, otherwise it is not. By default, the Secure attribute is not set.
Note be careful when setting this to true, as compliant clients will not send the cookie back to the server in the future if the browser does not have an HTTPS connection.
Please note that secure: true is a recommended option. However, it requires an https-enabled website, i.e., HTTPS is necessary for secure cookies. If secure is set, and you access your site over HTTP, the cookie will not be set. If you have your node.js behind a proxy and are using secure: true, you need to set "trust proxy" in express:
i am new in node js and i make a login system using session
and i am trying to store session data in database (i am using Xampp and phpmyadmin)
every thing is ok and req.session is available all over my application and session table created automatically in my database
but the session data didn't stored in my database and session table is EMPTY
and i don't know why ? is there any thing missed ?
const app = express();
const dotenv = require('dotenv');
const session = require('express-session');
const MySQLStore = require('express-mysql-session')(session);
const bcrypt = require('bcrypt');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const cookieParser = require('cookie-parser')
const port = process.env.port || 3100;
app.listen(port , (err)=> {
if (err) {
throw err;
}else {
console.log('LISTENING');
}
});
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: false }));
const connection = require('./db');
app.set('view engine' , 'ejs');
const sOpt = {
host: 'localhost',
user: 'root',
password: '',
database: 'pharma-app',
}
const sessionStore = new MySQLStore(sOpt);
app.use(session({
strore: sessionStore,
name: 'MyStrange-Cookie',
secret: 'pharma-app',
/*genid: function(req) {
return uuid() // use UUIDs for session IDs
},*/
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 60000
}
}))
app.get('/' , (req , res)=> {
console.log(`Session . User ID ${req.session.userid}`);
if (req.session.userid) {
res.render('index' , {id: req.session.userid});
}else {
res.render('index' , {id: 'login to see the user data'})
}
console.log(req.session);
})
app.post('/signin' , (req , res)=> {
req.session.userid = '456545654';
console.log(req.sessionID);
res.redirect('/');
})```
I use Nextjs and Express.js. I separate the nextjs root folder in the app folder like this :
app->pages->
-_app.js
-login.js
-index.js
When i add this :
app.get('*', (req, res) => {
const parsedUrl = parse(req.url,true);
const {pathname, query = {} } = parsedUrl;
const route = routes[pathname];
/**
* Pull in front end routes and check request against those routes
*
*/
if(route){
return app.render(req,res,route.page,query);
}
handle(req, res) // for all the react stuff
});
I got error like this :
Note that pages will be compiled when you first load them. ready at
http://localhost:3000 TypeError [ERR_INVALID_ARG_TYPE]: The "path"
argument must be of type string. Received type object
at assertPath (path.js:39:11)
at extname (path.js:835:5)
at new View (D:\WEBSITE\MENPRO\TRACER-STUDY-NEXTJS\node_modules\express\lib\view.js:57:14)
at Function.render (D:\WEBSITE\MENPRO\TRACER-STUDY-NEXTJS\node_modules\express\lib\application.js:570:12)
at app.get (D:\WEBSITE\MENPRO\TRACER-STUDY-NEXTJS\server\index.js:77:24)
But when i remove this : return app.render(req,res,route.page,query); its work again.
What happens with that ?
full code my server :
const express = require('express');
const bodyParser = require('body-parser');
const next = require('next');
const passport = require('passport');
const session = require('express-session');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const keys = require('./config/keys');
const uuidv4 = require('uuid').v4;
// const path = require('path');
// const RouteAPI = require('./modules');
const dev = process.env.NODE_ENV !== 'production';
const PORT = process.env.PORT || 3000;
const nextApp = next({ dev, dir: "./app" });
const { parse } = require('url');
const handle = nextApp.getRequestHandler()
const getRoutes = require('./routes');
const routes = getRoutes();
nextApp.prepare().then(() => {
// express code here
const app = express();
app.use(session({
genid: function (req) {
return uuidv4() // use UUIDs for session IDs
},
name: keys.session.name,
secret: keys.session.secret,
resave: false,
saveUninitialized: true,
rolling: true,
cookie: {
secure: false,
httpOnly: true,
maxAge: keys.session.maxAge, // satu hari,
sameSite: true,
}
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(cookieParser());
app.disable('x-powered-by');
app.use(cors({ origin: keys.origin.url, credentials: true }))
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// app.use((req, res, next) => {
// res.header('X-XSS-Protection', '1; mode=block');
// res.header('X-Frame-Options', 'deny');
// res.header('X-Content-Type-Options', 'nosniff');
// res.header("Access-Control-Allow-Origin", keys.origin.url);
// next();
// })
// app.use('/api/', [
// RouteAPI.MahasiswaRoutes
// ]);
app.get('*', (req, res) => {
const parsedUrl = parse(req.url,true);
const {pathname, query = {} } = parsedUrl;
const route = routes[pathname];
/**
* Pull in front end routes and check request against those routes
*
*/
if(route){
return app.render(req,res,route.page,query);
}
handle(req, res) // for all the react stuff
});
app.listen(PORT, err => {
if (err) throw err;
console.log(`ready at http://localhost:${PORT}`)
});
})
// Server static assets if in production
Routes
module.exports = () =>{
return{
"/":{page:"/"},
"/login":{page:"/login"},
"/404":{page:"/404"}
};
};
Ah yes, I've had the same issue and just found the solution: use nextApp.render() instead of app.render()
if(route){
return nextApp.render(req,res,route.page,query);
}
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