How to send cookies in express? - node.js

router.post('/login', async (req, res) => {
const logInEnvironment = browser(req.headers['user-agent']);
const ipAddress = requestIp.getClientIp(req);
const userEmail = req.body.userEmail.toLowerCase();
const password = req.body.password;
// Form validation
const validation = await validateLoginInput(req.body);
// Check validation
if (!validation.isValid) {
return res.status(400).json(validation.errors);
}
// Find user by email
const auth = await Auth.findOne({ userEmail }, { userLoginInfo: 0 });
//Check if user exists
if (auth === null) {
console.log('aaaa');
res.cookie('send2', 'shhhhhent!');
res.status(200);
return res
.status(400)
.json({ authFailedMessage: 'Email or password is incorrect' });
} else if (auth !== null) {
bcrypt.compare(password, auth.password).then((isMatch) => {
if (isMatch) {
return res.cookie('failed', 'yess!').status(200).json({succeeded: 'hiii'})
} else if (!isMatch) {
return res.cookie('succeeedd', 'noooo!').status(400).json({failed: 'hiii'})
}
});
}
});
I have this code. But, the res.json has been returned without cookies.
Moreover, I added these commands in my index.js file
const cookieParser = require('cookie-parser');
app.use(cookieParser());
I also tested if res.cookie() was working in another route
router.get('/cookie', (req, res) => {
res.cookie('hellooo', 'hiiiiii')
res.send('woooorked?')
})
This was returning cookie and I can see that in the dev-panel on Chrome. What have I done wrong in the first code that cookies are not sent to the browser?

Did you try to split the code like
router.get('/cookie', (req, res) => {
res.cookie('hellooo', 'hiiiiii')
res.send('woooorked?')
})
Can you test with this code
router.post('/login', async (req, res) => {
const logInEnvironment = browser(req.headers['user-agent']);
const ipAddress = requestIp.getClientIp(req);
const userEmail = req.body.userEmail.toLowerCase();
const password = req.body.password;
// Form validation
const validation = await validateLoginInput(req.body);
// Check validation
if (!validation.isValid) {
return res.status(400).json(validation.errors);
}
// Find user by email
const auth = await Auth.findOne({ userEmail }, { userLoginInfo: 0 });
res.cookie('send2', 'shhhhhent!');
return res.json({ authFailedMessage: 'Email or password is incorrect' });
});
Then you check the header of the request and find the header name set-cookie, if it visible, you have got it

Related

Node.js when I update a user it un-hash's the password

So im trying to make an admin login and I can get it to hash the password. But when I update the password or even the username it will un-hash the passwor for me when i need it to stay hashed. When I check my MongoDB itll be un-hashed for some reason. Any help will be appreciated. Thank you.
This is my user route
var express = require("express");
var router = express.Router();
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const { isAuthenticated } = require("../middleware/auth");
const Admin = require("../models/Admin");
const saltrounds = 10;
/* GET users listing. */
router.get("/", function (req, res, next) {
res.send("respond with a resource");
});
router.post("/login", async (req, res) => {
if (!req.body.username || !req.body.password) {
return res.json({ message: "Please enter username and password" });
}
try {
const foundUser = await Admin.findOne({ username: req.body.username });
if (!foundUser) {
return res
.status(400)
.json({ message: "Username or password is incorrect" });
}
const isMatch = bcrypt.compareSync(req.body.password, foundUser.password);
if (!isMatch) {
return res
.status(400)
.json({ message: "Username or password incorrect" });
}
const payload = {
username: foundUser.username,
id: foundUser._id,
};
const token = jwt.sign(payload, process.env.SECRET, {
algorithm: "HS256",
expiresIn: "6h",
});
res.json({ token: token, id: foundUser.id });
} catch (err) {
res.status(400).json(err.message);
}
});
router.post("/update", isAuthenticated, async (req, res) => {
try {
const updateUser = await Admin.findByIdAndUpdate(
req.user.id,
{ ...req.body },
{ new: true }
);
res.json(updateUser);
} catch (err) {
res.json(err.message);
}
});
module.exports = router;
This is my authenticated folder
const jwt = require("jsonwebtoken");
const isAuthenticated = async (req, res, next) => {
// const token = req.headers.authorization;
// NOTE: if your token authentication is failing in Postman, uncomment the line below, and comment out the line above
const token = req.headers.authorization?.split(" ")[1];
if (!token || token === "null") {
console.log("NO TOKEN");
return res.status(400).json({ message: "Token not found" });
}
try {
const tokenInfo = jwt.verify(token, process.env.SECRET);
console.log(tokenInfo);
//If you have req.payload, change line 12 to:
// req.payload = tokenInfo;
req.user = tokenInfo;
next();
} catch (error) {
return res.status(440).json(error);
}
};
// Export the middleware so that we can use it to create a protected routes
module.exports = {
isAuthenticated,
};
I think the issue is located at the (function)
Admin.findByIdAndUpdate
May be the find unhash the password fisrt and the update do not hash it again.
Check at this function.

How to use jwt in koa2 & nodejs

I have a page written in nodejs and koa, and I'm a little confused about JWT, please check following code.
'use strict';
const Router = require("koa-router");
const router = new Router({prefix: '/login'});
const jwt = require('jsonwebtoken');
const jwtkey = "123456";
router
.get('/', async (ctx, next) => {
await ctx.render("login", {
});
})
.post('/', async (ctx, next) => {
try {
let email = ctx.request.body.email || "";
let password = ctx.request.body.password || "";
//check user
if (islogin) {
let payload = {
email: email,
password: sha1(password).toString()
}
let token = jwt.sign(payload, jwtkey, {expiresIn: '3h'});
ctx.body = {"error": false, "msg": token};
} else {
throw "Wrong";
}
} catch (e) {
ctx.body = {error:true, msg: e instanceof Error ? e.message : e};
}
})
module.exports = router;
I want to implement that when accessing the login page, if the token generated by jwt exists on the server side and is correct, then console.log("logined"),if not, show the login page.
.get('/', async (ctx, next) => {
//how to verify the token?
if(token) {
console.log("logined");
} else {
await ctx.render("login", {
});
}
})
Thank you.
After generating the token you should set that token in user's browser as cookie or some other way,
Then while requesting / page check for the token and verify the validity
var decoded = jwt.verify(token, key);

How can I handle data/json that I retrieve from my API Webservice (ExpressJS)?

I'm new to NodeJS and ExpressJS. I created an AuthController which handles the login post.
exports.login = async (req, res, next) => {
try {
const email = req.body.email;
const password = req.body.password;
const user = await User.findOne({ email }).select("+password");
if (!user) {
const error = new Error("Wrong Credentials");
error.statusCode = 401;
throw error;
}
const validPassword = await user.validPassword(password);
if (!validPassword) {
const error = new Error("Wrong Credentials");
error.statusCode = 401;
throw error;
}
const token = jwt.encode({id: user.id}, config.jwtSecret);
res.send({user, token});
} catch(err) {
next(err);
}
}
I would like to use this method in my web application to let the user login. If the user succesfully logs in, I get a json response in my browser with the user and the token. That's not what I want. The url for the api login is: /api/auth/login. I created a function in my web application:
router.post('/login', async (req, res, next) => {
var apiResponse = await authController.login(req, res, next);
res.render('profile.ejs', {user: apiResponse.user});
});
I keep getting the error that authController.login is not a function. My question is how can I use the method from my API and use the response in my webapplication? Can someone help me out?
You can do it like this code below: 👇
router.post('/login', authController.login, async (req, res, next) => {
res.render('profile.ejs', {user: apiResponse.user});
});
👨‍🏫 Please read the documentation about Express Middleware.
Updated: Middleware
Make sure your authController looks like this code below:
exports.login = async (req, res, next) => {
try {
const email = req.body.email;
const password = req.body.password;
const user = await User.findOne({ email }).select("+password");
if (!user) {
const error = new Error("Wrong Credentials");
error.statusCode = 401;
throw error;
}
const validPassword = await user.validPassword(password);
if (!validPassword) {
const error = new Error("Wrong Credentials");
error.statusCode = 401;
throw error;
}
const token = jwt.encode({id: user.id}, config.jwtSecret);
// passing your data to next function
// you can change exampleData with the 'variable' you want
req.exampleData = { user, token }
next();
} catch(err) {
next(err);
}
}
If your authController is same root ("folder") with the your routes, than make it's look like this:
const { login } = require('./authController');
So, now, you can call the authController like this:
router.post('/login', login, async (req, res, next) => {
// your data: "user" and "token" from middleware
const { exampleData } = req;
console.log(exampleData);
res.render('profile.ejs', {user: exampleData});
});
I hope it's can help you 🙏.

Getting [jwt is not defined] while fetching data from MongoDB backend -

the question is pretty self explanatory. I am registering/signing up users in a mongoDB database. They are being registered fine and an accesstoken [jwt based] is also being generated.
Now, when I go to query the database to fetch the list of users I am getting that error -
jwt is not defined.
It is worthwhile to mention that users also in my backend can have two type of roles - basic and admin. And only an admin user can fetch list of all users by sending accessToken in the header as Bearer authorization parameter.
I have 2 main files in my backend project structure that uses jwt.access methods like jwt.verify or jwt.signIn; these are the server.js and userController.js [a separate file where I have written all individual db related methods].
As far as I am concerned, all necessary packages are there in my project - express, node, jwa, jws, jsonwebtoken, mongo, mongoose, bcrypt, cors etc. So what is the trouble?
My route.js -->
const User = require('../models/user.model');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const { roles } = require('../models/roles');
const JWT_SECRET = "$#GR24T4344$#$##%ETWWTEME%$6";
async function hashPassword(password) {
return await bcrypt.hash(password, 10);
}
async function validatePassword(plainPassword, hashedPassword) {
return await bcrypt.compare(plainPassword, hashedPassword);
}
exports.grantAccess = function (action, resource) {
return async (req, res, next) => {
try {
const permission = roles.can(req.user.role)[action](resource);
if (!permission.granted) {
return res.status(401).json({
error: "You don't have enough permission to perform this action"
});
}
next();
} catch (error) {
next(error);
}
}
}
exports.allowIfLoggedin = async (req, res, next) => {
try {
const user = res.locals.loggedInUser;
if (!user)
return res.status(401).json({
error: "You need to be logged in to access this route"
});
req.user = user;
next();
} catch (error) {
next(error);
}
}
exports.signup = async (req, res, next) => {
try {
const { role, email, password } = req.body;
const hashedPassword = await hashPassword(password);
const newUser = new User({ email, password: hashedPassword, role: role || "basic" });
const accessToken = jwt.sign({ userId: newUser._id }, JWT_SECRET, {
expiresIn: "1d"
});
newUser.accessToken = accessToken;
await newUser.save();
res.json({
data: newUser,
message: "You have signed up successfully"
});
} catch (error) {
next(error);
}
}
exports.login = async (req, res, next) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user)
return next(new Error('Email does not exist'));
const validPassword = await validatePassword(password, user.password);
if (!validPassword)
return next(new Error('Password is not correct'));
const accessToken = jwt.sign({ userId: user._id }, JWT_SECRET, {
expiresIn: "1d"
});
await User.findByIdAndUpdate(user._id, { accessToken });
res.status(200).json({
data: { email: user.email, role: user.role },
accessToken
});
} catch (error) {
next(error);
}
}
exports.getUsers = async (req, res, next) => {
const users = await User.find({});
res.status(200).json({
data: users
});
}
exports.getUser = async (req, res, next) => {
try {
const userId = req.params.userId;
const user = await User.findById(userId);
if (!user)
return next(new Error('User does not exist'));
res.status(200).json({
data: user
});
} catch (error) {
next(error);
}
}
exports.updateUser = async (req, res, next) => {
try {
const { role } = req.body;
const userId = req.params.userId;
await User.findByIdAndUpdate(userId, { role });
const user = await User.findById(userId);
res.status(200).json({
data: user
});
} catch (error) {
next(error);
}
}
exports.deleteUser = async (req, res, next) => {
try {
const userId = req.params.userId;
await User.findByIdAndDelete(userId);
res.status(200).json({
data: null,
message: 'User has been deleted'
});
} catch (error) {
next(error);
}
}
My server.js -->
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const PORT = 4000;
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const playerRoutes = express.Router();
const userRoutes = express.Router();
const userController = require('./controllers/userController');
const user_routes = require('./apiroutes/route');
const app = express();
const JWT_SECRET = "$#GR24T4344$#$##%ETWWTEME%$6";
const users = "users";
require("dotenv").config({path: __dirname+ '../.env'});
let Player = require('./models/player.model');
let User = require('./models/user.model');
app.use(cors());
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: false
})
);
mongoose.connect('mongodb://127.0.0.1:27017/playerDB', function (err, db) {
if (err)
throw err;
db.createCollection(users, function (err, resp) {
if (err)
throw err;
console.log("Collection created!");
});
}, { useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function () {
console.log("MongoDB database connection established successfully");
});
..... blablablaaaa
app.use('/playerDB', playerRoutes);
app.use(async (req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
if (req.headers["x-access-token"]) {
try {
const accessToken = req.headers["x-access-token"];
const { userId, exp } = await jwt.verify(accessToken, JWT_SECRET);
// If token has expired
if (exp < Date.now().valueOf() / 1000) {
return res.status(401).json({
error: "JWT token has expired, please login to obtain a new one"
});
}
res.locals.loggedInUser = await User.findById(userId);
next();
} catch (error) {
next(error);
}
} else {
next();
}
});
app.use('/users', user_routes);
app.listen(PORT, function () {
console.log("Server is running on Port: " + PORT);
});
I hope you understand my approach and scenario? Can you guess, where it could have gone wrong? Any idea?
Missing npm packages or something more critical?
Look forward to some hints on this problem! Can't seem to figure out a way!
it seems you forgot to add this line to server.js
const jwt = require('jsonwebtoken');
While register and login, this didn't caused a problem, because for these requests, req.headers["x-access-token"] was null, and the code didn't reach the if block where you used jwt, but one a request with this header came (like getUsers) the code tried to use jwt.verify, but since jwt wasn't imported it gave error.

How to get session data for API requests?

I want to get authorized user data. But instead I get the data of a completely different user. How to write a function getProfile to display the data of the current user?
controllers/auth.js:
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const db = require('../config/db.config.js')
const User = db.user
module.exports.login = async function(req, res) {
const candidate = await User.findOne({
where: {
username: req.body.username
}
})
if (candidate) {
const passwordResult = bcrypt.compareSync(req.body.password, candidate.password)
if (passwordResult) {
const token = jwt.sign({
username: candidate.username,
userId: candidate._id
}, process.env.SECRET_OR_KEY, {expiresIn: 60 * 60})
res.status(200).json({
token: `Bearer ${token}`
})
} else {
res.status(401).json({
message: 'Passwords do not match. Try again.'
})
}
} else {
res.status(404).json({
message: 'User with this login was not found.'
})
}
}
module.exports.getProfile = async function(req, res) {
try {
const user = await User.findOne({id: req.body.id})
res.status(200).json(user)
} catch(e) {
errorHandler(res, e)
}
}
routes/auth.js:
const express = require('express')
const router = express.Router()
const controller = require('../controllers/auth')
const passport = require('passport')
router.post('/login', controller.login)
router.get('/profile', passport.authenticate('jwt', {session: false}), controller.getProfile)
module.exports = router
You should attach a signed token in each HTTP req from client, either by custom HTTP header or set in cookie. This token is sent only after successful login which contains user's id and other info.
After you start receiving that token you can validate it (checking for expiry or some manual change) using a middleware and that token data will be the actual user data belongs to the user loggedin.
Now, you read that header/cookie to get requester user's info and you can then send their respective data only.
Let's say if client is sending you token info in header called tkn. Your token validation can be as follows:
var jwt = require('jsonwebtoken');
const SECRET = 'whatulike';
function verifyToken(req, res, next) {
var token = req.headers.tkn || "";
if (!token.length)
return unauthorised(res, 'Token absent');
jwt.verify(token, SECRET, function(err, decoded) {
if (err)
return unauthorised(res, 'Failed to authenticate token.');
req.tkn = decoded.id;
next();
});
}
function unauthorised(res, msg){
const sc = 401;
logger.warn(`${sc} - Unauthorised request ${res.req.originalUrl}`);
res.status(sc).send({msg});
}
module.exports.verifyToken = verifyToken;
And at handler side you can read tkn data like:
module.exports.getProfile = async function(req, res) {
try {
const user = await User.findOne({id: req.tkn.userId})
res.status(200).json(user)
} catch(e) {
errorHandler(res, e)
}
}

Resources