I'm having trouble with express-sessions while running on localhost. When I call req.session in development it only retrieves part of my session cookie. But it works fine in production. my app.js file is as follows:
const path = require("path");
const express = require('express');
const cookieParser = require('cookie-parser')
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const mongoose = require('./db/mongoose');
const PORT = process.env.PORT;
const retrieveUserIdFromRequest = require("./middleware/get-user.middleware");
const MONGODB_URI = `mongodb+srv://${process.env.MONGO_USER}:${process.env.MONGO_PW}#cluster0.mongodb.net/test`
const app = express();
var store = new MongoDBStore({
uri: MONGODB_URI,
collection: 'sessions',
});
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PATCH, PUT, DELETE, OPTIONS"
);
next();
});
const usersRoutes = require("./routes/users");
const loginsRoutes = require("./routes/logins");
const accountsRoutes = require("./routes/accounts");
const projectsRoutes = require("./routes/projects");
app.use(express.json());
app.use(express.urlencoded({extended: true}));
app.use(cookieParser())
app.use("/", express.static(path.join(__dirname,'angular')));
var hour = 3600000
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
store: store,
cookie: {
path: '/',
httpOnly: true,
secure: true,
maxAge: hour,
expires: new Date(Date.now() + hour),
sameSite: true
}
}));
app.use(retrieveUserIdFromRequest);
app.use((req, res, next) => {
console.log('req.session.user app.js', req.session)
next();
});
app.use('/api/users' , usersRoutes)
app.use('/api/logins' , loginsRoutes)
app.use("/api/accounts", accountsRoutes);
app.use("/api/projects", projectsRoutes);
app.use((req, res, next) => {
res.sendFile(path.join(__dirname, "angular", "index.html"));
});
app.listen(PORT, () => {
console.log("Server is listening on port " + PORT);
})
module.exports = app;
my login route is as follows:
exports.login = async (req, res) => {
await User.findOne({ email: req.body.email })
.then(async(user) => {
let obj = user.toJSON()
obj.instances = await user.buildAccess()
const fetchedUser = await obj;
if (!fetchedUser) {
res.status(200).json({
message: 'Could not find e-mail in database.'
})
} else {
if(user.activated){
loginAndBuildResponse(req, res, fetchedUser);
req.session.isLoggedIn = true
req.session.user = {
_id: fetchedUser.id,
email: fetchedUser.email,
access: fetchedUser.access
}
req.session.save()
} else {
res.status(200).json({
message: 'Your account has not been activated. Please check your email for your activation link.'
})
}
}
});
}
While in development, when I call req.session it does not retrieve the session.isLoggedIn or session.user data as I would expect, or as it does in production. Does anyone have any ideas why this might be the case or where i am going wrong?
Related
I am using nodejs api for doing twitter authentication. I have deployed nodejs api on firebase functions. I have also read documentation about IMA and set allUsers roles inside google cloud console. If I try to go with /hello endpoint then my code is working fine and I can see result on my screen. But when I am doing res.redirect() then I got error of
Error: Forbidden Your client does not have permission to get URL /twitter/login from this server.
const functions = require("firebase-functions");
var express = require('express');
var path = require('path');
// var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');
var Strategy = require('passport-twitter').Strategy;
var session = require('express-session');
const firebase = require('firebase');
const port = 3000
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
};
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
const Users = db.collection("users")
passport.use(new Strategy({
consumerKey: '',
consumerSecret: '',
callbackURL: ''
}, function (token, tokenSecret, profile, callback) {
return callback(null, profile);
}));
passport.serializeUser(function (user, callback) {
callback(null, user);
})
passport.deserializeUser(function (obj, callback) {
callback(null, obj);
})
var app = express();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({ secret: 'whatever', resave: true, saveUninitialized: true }))
app.use(passport.initialize())
app.use(passport.session())
app.get('/', function (req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,PATCH,POST,DELETE");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if (req.user == undefined) {
// res.json({"message": "All ok"})
res.redirect('/twitter/login')
}
else if (req.user != undefined) {
return;
}
})
app.get('/hello', function (req, res) {
res.json({"message": "Hello"})
})
app.get('/twitter/login', passport.authenticate('twitter', {
failureRedirect: '/'
}))
app.get('/twitter/sucess', function (req, res) {
console.log("in twitter success")
console.log(req.user.username);
console.log(req.user);
res.cookie("twitter_id", req.user.id, { expires: new Date(Date.now() + (7300 * 24 * 3600000)) });
const userRef = db.collection("users").doc(req.user.id)
userRef.get()
.then((docSnapshot) => {
if (docSnapshot.exists) {
} else {
userRef.set({"userName": req.user.username, "twitterId": req.user.id, "displayName": req.user.displayName, "crushCount": 0}) // create the document
}
});
res.redirect("http://localhost:8000/add_crush");
// res.status(200).json({"message": "Auth Successfull", "username": req.user.username})
})
app.get('/twitter/return', passport.authenticate('twitter', {
failureRedirect: '/',
successRedirect: '/twitter/sucess',
}), function (req, res) {
})
app.listen(port, () => console.log(`Listening on port ${port}`))
exports.app = functions.https.onRequest(app)
Here is my code, please suggest what to do?
There can be multiple reasons behind the error you’re receiving.Usually, this is due to the way that you are authenticating on Firebase.
Considering that, I would recommend you to take a look at the following Community posts 1,2 &3 for more information, on alternatives to fix the error.
You can take a look at this documentation on Nodejs twitter login script with passport.js
I work with reactjs and nodejs(express) . so what i want to do is store a token generated using JWT in a cookie and send it to the front end.
The problem is that the cookie is not displayed in the browser !
front end work on port 3000 (localhost:3000)
for the backend it works on port 3006 (localhost:3006)
here my app.js (server side)
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
require("dotenv").config();
var indexRouter = require("./routes/index");
const Pool = require("pg");
const cors = require("cors");
var app = express();
app.use(
cors({
origin: "http://localhost:3000",
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
})
);
//preventing Cors error
app.use((req, res, next) => {
res.header("Content-Type", "application/json;charset=UTF-8");
res.header("Access-Control-Allow-Credentials", true);
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
app.use("/api", indexRouter);
module.exports = app;
my index.js
var express = require('express');
const { Register, Login, Check} = require('../controllers/Users.controller');
var router = express.Router();
const auth = require('../middleware/auth')
// routes for inscription
router.post('/inscrire', Register)
router.post('/login', Login)
router.get('/islogged', auth, Check)
module.exports = router;
and here is the controller
const Login = (req, res, next) => {
const { email, motdepass } = req.body.values;
pool
.query("SELECT * FROM public.user WHERE email = $1", [email])
.then((result) => {
if (result.rowCount == 0) {
return res.status(401).json({ error: "Utilisateur non trouvé !" });
} else {
bcrypt
.compare(motdepass, result.rows[0].motdepass)
.then((valid) => {
if (!valid) {
return res
.status(401)
.json({ error: "Mot de passe incorrect !" });
}
const token = jwt.sign(
{ userId: result.rows[0]._id },
process.env.TOKEN,
{ expiresIn: "24h" }
);
res.cookie("jwt", token, {
httpOnly: false,
secure: false,
maxAge: 6000000 * 60,
});
res.status(200).json({
userId: result.rows[0]._id,
email: result.rows[0].email,
token: token,
});
})
.catch((error) => {
res.status(500).json({ message: "Mot de pass invalide !" });
console.log(error);
});
}
})
.catch((error) => res.status(500).json({ message: "invalide password" }));
};
in the front side we have the function :
const handleLogin = (values) => {
axios
.post("http://localhost:3006/api/login", {
values,
withCredentials: true,
credential: 'include'
})
.then((response) => {
setUser(response.data.email);
setError(true);
auth.login(user);
// navigate('/')
})
.catch((err) => {
setError(false);
});
}
Note : i can see the set-cookie at response Headers
I am logging in successfully, however, I am getting unauthorized when I'm trying to access my authenticated-only route. I don't understand what I am doing wrong here, it successfully logs me in and returns the user, where am I wrong?
Here's my code:
This here is basically the server configuration for the backend.
server.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors')
const passport = require('passport')
// passport
const cookieParser = require('cookie-parser')
const session = require('cookie-session')
const { COOKIE_NAME } = require('./client/src/common/config')
const app = express();
// Bodyparser Middleware
app.use(bodyParser.json());
// DB Config
const db = require ('./config/keys').mongoURI;
// Connect to MongoDB
mongoose
.connect(db, {useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false})
.then(() => console.log('Mongo DB Connected...'))
.catch(err => console.log(err));
// CORS
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
const secret = process.env.APP_SECRET
const env = process.env.NODE_ENV || 'development'
const isLocal = env === 'development'
/* Session Setup */
app.use(cookieParser()) // read cookies (needed for auth)
if (!isLocal) {
app.set('trust proxy', 1)
}
app.use(
session({
httpOnly: false,
name: COOKIE_NAME,
keys: [secret],
secure: !isLocal,
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
})
)
/* Session management with Passport */
require('./passport')(passport)
app.use(passport.initialize())
app.use(passport.session())
// Register Schema
require('./models/User')
// Insert some default users
// require('./config/_insertDefaultUsers')
const patients = require('./routes/api/patients');
const auth = require('./routes/api/auth');
const drugs = require('./routes/api/drugs');
const trainees = require('./routes/api/trainees')
// Use Routes
app.use('/api/patients', patients);
app.use('/api/drugs', drugs);
app.use('/api/trainees', trainees)
app.use('/api/auth', auth);
app.use(cors())
// Connect to deployment port or localhost
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server started on port ${port}`));
access.js this is a basic middleware to check for authentication, so I can add it in my routes
const ROLES = require('.././client/src/common/roles')
/** Access middleware to ensure user is allowed to access certain routes */
const AccessMiddleware = {
hasAccess: (req, res, next) => {
if (!req.isAuthenticated()) {
req.session.redirectTo = req.originalUrl
return res.status(401).json({ success: false, error: 'unauthorized' })
}
next()
},
hasAdminAccess: (req, res, next) => {
if (!req.isAuthenticated() || req.user.role !== ROLES.ADMIN) {
req.session.redirectTo = req.originalUrl
return res.status(401).json({ success: false, error: 'unauthorized' })
}
next()
},
}
module.exports = AccessMiddleware
auth.js route and this is basically the authentication API which allows me to login and so on
const express = require('express');
const router = express.Router();
const passport = require('passport')
const AccessMiddleware = require('../../config/access')
const errorResponse = (res, error) => {
res.status(400).json({ success: false, error })
}
router.get('/test', (req, res) => {
res.json({ success: true, message: 'Test API route working fine!' })
})
router.get('/authenticated-only', AccessMiddleware.hasAccess, (req, res) => {
res.json({ success: true, message: 'You have auth access!' })
})
router.get('/admin-only', AccessMiddleware.hasAdminAccess, (req, res) => {
res.json({ success: true, message: 'You have admin access!' })
})
router.post('/login', (req, res, next) => {
const { email, password } = req.body
if (!email || !password) {
return errorResponse(res, 'Invalid credentials')
}
// Authenticate the user using the credentials provided
passport.authenticate('local', { session: true }, function (err, user) {
if (err) {
return errorResponse(res, 'Invalid credentials')
}
// When using passport with callback, we have to manually call req.login to set the Cookie
req.login(user, async () => {
res.json({ success: true, user })
})
})(req, res, next)
})
module.exports = router
exports.errorResponse = errorResponse
For anyone looking for a solution:
const secret = "secrethere"
app.use(cookieParser("secrethere"))
The issue seems to have been that I was not using the same secret within the server file.
What I'm trying to do is get json data from "/get" to "/", but I'm not sure why axios keeps giving my a 403 error. From what I read, axios isn't the issue, but cors is. I tried all the ways that people are recommending, but nothing is working. What I'm I doing wrong within my code? I'm also seeing "Referrer Policy: strict-origin-when-cross-origin" in the Header, but I'm not sure if that's what's causing this issue.
const express = require("express");
const mysql = require("mysql2");
var app = express();
const bodyparser = require("body-parser");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const expressSession = require("express-session")({
secret: "secret",
resave: false,
saveUninitialized: false,
});
const passport = require("passport");
const jwt = require('jsonwebtoken');
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyparser.json());
app.use(cors());
app.use(bodyparser.urlencoded({ extended: false }));
app.use(express.json());
app.use(cookieParser());
app.use(expressSession);
const axios = require('axios');
var mysqlConnection = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "sys",
multipleStatements: true,
});
mysqlConnection.connect((err) => {
if (!err) console.log("DB connection succeded.");
else
console.log(
"DB connection failed \n Error : " + JSON.stringify(err, undefined, 2)
);
});
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'DELETE, PUT, GET, POST');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.listen(5000, () =>
console.log("Express server is runnig at port no : 5000")
);
app.get("/get", authenticateToken, (req, res) => {
jwt.verify(req.token, 'secretpassword', (err) => {
if (err) {
res.sendStatus(403);
} else {
mysqlConnection.query("SELECT * FROM sys.jobs", (err, rows) => {
if (rows === undefined) {
res.send("Hello World!");
} else {
res.send(rows);
}
});
}
});
});
app.get("/", authenticateToken, (req, res) => {
jwt.verify(req.token, 'secretpassword', async (err) => {
if (err) {
res.sendStatus(403);
} else {
let response = await axios.get('http://localhost:5000/' +'get', {
withCredentials: true,
headers: {
'Access-Control-Allow-Origin': '*',
'Authorization': `Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjAwOTIyMTQ0LCJleHAiOjE2MDg2OTgxNDR9.aRsw-
jEQJ-7mlO10nBKA5VT3IL7P0b9T9K0C8aT8sUs`
}
});
res.send(response.data);
}
});
});
app.post("/login", async (req, res) => {
try {
const { email } = req.body;
mysqlConnection.query("SELECT * FROM sys.users WHERE email = ?", [email], async (error, results) => {
const id = results[0].id;
const token = jwt.sign({ id }, "secretpassword", {
expiresIn: '90d'
});
const cookieOptions = {
expires: new Date(
Date.now() + 90 * 24 * 60 * 60 * 1000
),
secure: false,
httpOnly: true
}
res.cookie('jwt', token, cookieOptions);
res.status(200).redirect("/get");
});
}
catch (error) {
console.log(error);
}
}
);
function authenticateToken(req, res, next) {
const bearerHeader = req.cookies.jwt;
if (typeof bearerHeader !== 'undefined') {
req.token = bearerHeader;
next();
} else {
res.sendStatus(403);
}
}
use cors module
const cors = require('cors')
//... your app instance code here
app.use(cors())
app.js
const mongoose = require('mongoose');
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const MONGODB_URI =
'mongodb+srv://#cluster0-szxlh.mongodb.net/shop';
const store = new MongoDBStore({
uri: MONGODB_URI,
collection: 'sessions'
});
app.use(
session({
secret: 'my secret',
resave: false,
saveUninitialized: false,
store: store
})
);
app.use((req, res, next) => {
console.log("in app");
res.locals.isAuthenticated = req.session.isLoggedIn;
res.locals.isShopAuthenticated = req.session.isShopLoggedIn;
res.locals.isUserAuthenticated = req.session.isUserLoggedIn;
res.locals.islat=req.session.lat;
res.locals.islang=req.session.lang;
res.locals.csrfToken = req.csrfToken();
console.log(req.session.lat); //returns wrong(previous)value
console.log(req.session.lang); //returns wrong(previous)value
next();
});
app.use(function (req, res, next) {
res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
next();
});
post request which sets the cookie
exports.postHome=(req,res,next)=>{
const lattitude=req.body.lattitude;
const longitude= req.body.longitude;
req.session.lat=lattitude; //setting session
req.session.lang=longitude;
req.session.save();
console.log("inpost");
console.log(lattitude);
console.log(longitude);
res.redirect('/');
}
I have used routes after the session middleware.
I have checked in database the value got updated but req.session.lat in app.js returns previously updated value some times
logs
inpost
13.336614284510889
80.19245464019774 in app
13.336614284510889
80.19245464019774
inpost
13.334818684323631
80.18992263488768 in app
13.336614284510889 (check it returns previous value sometimes)
80.19245464019774
exports.postHome=(req,res,next)=>{
const lattitude=req.body.lattitude;
const longitude= req.body.longitude;
req.session.lat=lattitude; //setting session
req.session.lang=longitude;
req.session.save(err=>{
if(!err)
{
console.log("inpost");
console.log(lattitude);
console.log(longitude);
res.redirect('/');
}
})
}
if req.session.save is synchronized its working correctly.