can't see the cookie on the browser sent by server - node.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

Related

Express Session problem running on localhost

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?

I cant access the req.user from passport outside of my routes folder. MERN stack redux node.js

I am trying to access the req.user that passport creates when doing a google o auth strategy. I can access the req.user in the routes file below, but when I try to access it in my userController file it is showing up as undefined.
Why is user accessible in routes file but not userController?
googleAuthRoutes.js:
const passport = require('passport');
const requireLogin = require('../middlewares/requireLogin')
const cors = require('cors');
const axios = require('axios');
const Template = require('../models/Template');
const corsOptions ={
origin: true,
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200
}
module.exports = app => {
app.get('/auth/google',
passport.authenticate('google', {
scope: ['profile', 'email']
}));
app.get(
'/auth/google/callback',
passport.authenticate('google'),
(req, res) => {
res.redirect('/dashboard');
}
);
app.post('/templates/create', async (req, res) => {
const { template, body } = req.body
console.log(req.user)
const newTemplate = new Template({
template: template,
body: body,
_user: req.user.id
})
try {
await newTemplate.save()
return res.status(200).json({
message: "Successfully saved template"
})
} catch (err) {
return console.log(err)
}
});
app.get('/api/logout', cors(), (req, res) => {
req.logout();
res.redirect('http://localhost:3000');
});
app.get('/api/current_user', (req, res) => {
res.send(req.user);
})
}
when I call the res.send(req.user) here above it sends the user no problem
But it is undefined with the /templates/create route middleware.
the console.log(req.user) is coming back as undefined??
index.js:
const express = require('express');
const cors = require('cors')
const mongoose = require('mongoose');
const cookieSession = require('cookie-session');
const passport = require('passport');
const keys = require('./config/keys');
const bodyParser = require('body-parser')
require("dotenv").config();
require('./models/GoogleUserModel'); // the user model must be placed before this services passport// this must be ran after requiring model bcuz this needs the model. ORDER
require('./models/UserModel');
require('./services/passport');
const corsOptions ={
origin:'http://localhost:3000',
credentials: true, //access-control-allow-credentials:true
optionSuccessStatus:200
}
const app = express();
app.use(cors(corsOptions))
mongoose.connect(keys.mongoURI, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
})
mongoose.connection.on('error', () => {
throw new Error (`unable to connect to database: ${keys.mongoURI}`)
});
app.use(bodyParser.json())
app.use(express.urlencoded( { extended: true }))
app.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: [keys.cookieKey]
})
)
app.use(passport.initialize());
app.use(passport.session());
require('./routes/userRoutes')(app);
require('./routes/googleAuthRoutes')(app);
require('./routes/messageRoutes')(app);
app.use((err, req, res, next) => {
if (err.name === 'UnauthorizedError') {
res.status(401).json({"error" : err.name + ": " + err.message})
} else if (err) {
res.status(400).json({"error" : err.name + ": " + err.message})
console.log(err)
}
})
const PORT = process.env.PORT || 5000;
app.listen(PORT);
Again, Why is the req.user available in the app.get to /api/current_user but available in a post request to /templates/create?
Im trying to add the user.id to the schema when it saves so i can retrieve each template by the user.id and not show everyone everybody elses templates lol

Unauthorized when logged in?

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.

Using axios to get data from "/get" to "/", but geting 403 error. (Express, mysql, JWT)

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())

Post request from react app stalls after deploying to Heroku

I've made this app using the MERN stack and am facing problems while deploying to Heroku. I have a userContext.js file which handles authentication of users. It has a function which makes a post request to the server which in development is on localhost:80. This has been working fine in development and the request is successful. After deploying the same request stalls and fails. I don't understand how to get a response from the request. Any help is really appreciated. Thanks, Hatim
server.js
const express = require("express"),
http = require("http"),
app = express(),
server = http.createServer(app),
bodyParser = require("body-parser"),
mongoose = require("mongoose"),
passport = require("passport"),
cors = require("cors");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
app.use((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();
});
//IMPORT MODELS
require("./models/products");
require("./models/user");
//MONGOOSE CONNECT
mongoose.Promise = global.Promise;
mongoose
.connect(
process.env.MONGODB_URI || `mongodb://localhost:27017/technicalKwt`,
{
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false
}
)
.then(() => console.log("MONGODB Connected"))
.catch(err => {
console.log(err);
});
//SET FOR PRODUCTION
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/build"));
const path = require("path");
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
// Passport middleware
app.use(passport.initialize());
// Passport config
require("./config/passport")(passport);
require("./api/products")(app);
require("./api/transaction")(app);
require("./api/users")(app);
require("./api/genPDF")(app);
const port = process.env.PORT || 80;
server.listen(port, () => {
console.log(`Listening on port ${port}`);
});
users.js
app.post("/login", (req, res) => {
console.log(req.body);
const email = req.body.email;
const password = req.body.password;
User.findOne({ email }).then(user => {
if (!user) {
return res.status(401).json({ message: "Invalid Credentials" });
}
// Check password
bcrypt.compare(password, user.password).then(isMatch => {
if (isMatch) {
// User matched
// Create JWT Payload
const payload = {
id: user.id,
name: user.name
};
// Sign token
jwt.sign(
payload,
keys.secretOrKey,
{
expiresIn: 31556926 // 1 year in seconds
},
(err, token) => {
res.json({
success: true,
token: "Bearer " + token,
payload
});
}
);
} else {
return res.status(401).json({ message: "Invalid Credentials" });
}
});
});
});
loginUser function in userContext.js
function loginUser(dispatch, login, password, history, setIsLoading, setError) {
setIsLoading(true);
if (!!login && !!password) {
axios
.post('http://localhost:80/login', {
email: login,
password,
})
.then(res => {
localStorage.setItem('id_token', res.data.payload.id);
localStorage.setItem('name', res.data.payload.name);
setIsLoading(false);
dispatch({ type: 'LOGIN_SUCCESS' });
history.push('/app/products');
})
.catch(err => {
setIsLoading(false);
dispatch({ type: 'LOGIN_FAILURE' });
});
} else {
dispatch({ type: 'LOGIN_FAILURE' });
setIsLoading(false);
}
}
I'm making some assumptions about your app here.
On Heroku I believe you cannot use './' anymore. In your server.js try using the built-in '__dirname':
require(__dirname + "/models/users")
Second issue: Your userContext.js is presumably on the client-side now, as in a person views this on their browser. The path to your routes is no longer localhost:80 it's your heroku domain (something.com) so your axios post request needs the new url. Try this:
axios
.post('http://' + document.location.hostname + '/login', {
email: login,
password,
})

Resources