This is my app.post()which gets form data from client.
app.post('/api/login', async (req, res) => {
const { emailid, password } = req.body
const user = await User.findOne({ emailid }).lean()
if (!user) {
return res.json({ status: 'error', error: " Invalid username/Password" })
}
if (bcrypt.compare(password, user.password)) {
const token = jwt.sign({ id: user._id, emailid: user.emailid }, 'secret', { expiresIn: '24h' })
return res.json({ status: 'ok', data: token, user_id: user._id })
}
res.json({ status: 'error', error: " Invalid username/Password" })
})
I need to pass the jwt token or the user_id to my
app.get('/', (req,res)=>{
res.render('index')
})
For this, you will need to create an authentication middleware that will check your request headers for a jwt token, which you can then decode to get the user_id or any other data that you passed to it during encryption. A sample middleware can look like the one below
const isAuth = (req) => {
const authorization = req.headers["authorization"];
if (!authorization) throw new Error("You need to log in");
const token = authorization.split(" ")[1];
const { user_id} = verify(token, process.env.ACCESS_TOKEN_SECRET);
return {user_id, token};
};
After you setup your authorization middleware, you can then go ahead and use it in your routes like so
app.get('/', (req,res)=>{
const {token, user_id) = isAuth(req);
//use token and user_id here or throw error if not available in case this is a protected route
res.render('index')
})
Related
So I create my route user and I use this tutorial https://www.bezkoder.com/node-js-jwt-authentication-mysql/ to add the token and Authentication Token + validation name. Everything work great. But then when I beginning to create my route Comment (acces for every user), I had normaly the auth but even with the token Postman send me an "No token provided!". I have to add this token and autorize the acces but I don't know how. If somebody know how to do it, it would be great :D thx ! This is how I add my token on Postman
enter image description here
Here is my code:
My route comment:
const express = require("express");
const router = express.Router();
const commentCtrl = require("../controllers/comment");
const { authJwt } = require("../middleware");
router.post("/upload", [authJwt.verifyToken], commentCtrl.createComment);
module.exports = router;
The middleware token :
const jwt = require("jsonwebtoken");
const config = require("../config/auth.config.js");
verifyToken = (req, res, next) => {
let token = req.headers["x-access-token"];
if (!token) {
return res.status(403).send({
message: "No token provided!"
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Unauthorized!"
});
}
req.id = decoded.id;
next();
});
};
const authJwt = {
verifyToken: verifyToken,
};
module.exports = authJwt;
const authJwt = require("./authJwt");
const verifySignUp = require("./verifySignUp");
module.exports = {
authJwt,
verifySignUp
};
My verification SignUp:
const { User } = require("../models");
checkDuplicateEmail = async (req, res, next) => {
const user = await User.findOne({
where: {
email: req.body.email
}
}).then(user => {
if (user) {
res.status(400).send({
message: "Failed! Email is already in use!"
});
return;
}
next();
});
};
const verifySignUp = {
checkDuplicateEmail: checkDuplicateEmail
};
module.exports = verifySignUp;
And here is my user.controllers when is send the token:
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const config = require("../config/auth.config");
const { User } = require("../models");
module.exports.signup = async (req, res) => {
if (!req.body.email || !req.body.password) {
res.status(400).send({
status: false,
message: 'une erreur dans create est survenu'
});
} else {
let { nom, prenom, email, password, status} = req.body;
const salt = await bcrypt.genSalt(10);
password = await bcrypt.hash(password, salt)
const user = await User.create({
nom, prenom, email, password, status
})
.then((user) => res.status(201).send(user)).catch((error) => {
console.log(error);
res.status(400).send(error);
});
}
};
module.exports.login = async (req, res) => {
const user = await User.findOne({
where: {
email: req.body.email
}
})
.then(user => {
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
const passwordIsValid = bcrypt.compareSync(req.body.password, user.password);
if (!passwordIsValid) {
return res.status(401).send({
accessToken: null,
message: "Invalid Password!"
});
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400 // 24 hours
});
res.status(200).send({
id: user.id,
nom: user.nom,
email: user.email,
password: user.password,
accessToken: token
});
})
.catch(err => {
res.status(500).send({ message: err.message });
});
};
While it would have helped if you had provided a screenshot of where you are putting your token on postman, make sure you are using the appropriate header. According to your code, you are searching the 'x-access-token' header, so in postman, you should attach your jwt token to the same header property. It should be something like this:
postman x-access-token demo
I use JWT for auth.
The auth will be a middleware:
const jwt = require('jsonwebtoken');
require('dotenv').config();
module.exports = (req, res, next) => {
const token = req.header("auth-token");
if (!token) return res.status(401).send("Missing token. Access denied");
try {
const decoded = jwt.verify(token, process.env.jwtKey);
req.user = decoded;
next();
} catch (err) {
console.log(err);
res.status(400).send('Invalid token.');
}
};
now when I get an token and use it in header "auth-token" and making a get or post request with the auth middleware its allways gives me "JsonWebTokenError: invalid signature"
I use the middleware like this:
router.get('/:id', auth, async (req, res) => {
const user = await User.findOne({
_id: req.params.id,
});
if (!user) return res.status(404).send('User not found');
res.send(user);
})
here is where the token is generated
router.post('/', async (req, res) => {
//check for validation errors
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
let user = await User.findOne({ email: req.body.email });
if (!user) return res.status(404).send("Invalid email or password");
const validPassword = await bcrypt.compare(req.body.password, user.password);
if (!validPassword) return res.status(400).send("Invalid email or password");
res.json({ token: user.generateAuthToken(), status: "User is logged in" })
});
const validate = (req) => {
const schema = Joi.object({
email: Joi.string().min(6).max(255).email().required(),
password: Joi.string().min(6).max(255).required(),
});
return schema.validate(req);
};
module.exports = router;
You can see the auth middleware is used when I make the request GET
At JWT.io debugger when I put the token its says its ok... so whats worng?
So I sloved the issue, I had mistake with the key I decoded and key I veryfied.
In my project, when a user logs in, I generate an auth token like so:
// For my User model
userSchema.methods.generateAuthToken = () => {
const token = jwt.sign({ _id: this._id }, config.get('jwtPrivateKey'))
return token
}
I then apply an auth middleware on a route that allows a user to create posts.
auth middleware:
module.exports = (req, res, next) => {
const token = req.header('x-auth-token')
if (!token) return res.status(401).send('No token provided')
try {
const decoded = jwt.verify(token, config.get('jwtPrivateKey'))
req.user = decoded
next()
}
catch (ex) {
res.status(400).send('Invalid token')
}
}
My route:
router.post('/', auth, upload.single('postImage'), async (req, res) => {
console.log(req.user._id)
const post = new Post({
postImage: `http://localhost:3000/${req.file.path}`,
caption: req.body.caption,
user: req.user._id
})
await post.save()
res.send(post)
})
As you can see, I log the req.user._id in the route, and when I call this endpoint, I get undefined logged to the console. Instead I expect the _id of the user who generated the auth token.
Below is my login route, where a user gets their auth token.
Login route:
router.post('/', validateLogin, async (req, res) => {
const errors = validationResult(req)
if (!errors.isEmpty()) return res.status(422).send(errors.array())
let user = await User.findOne({ $or: [{ username: req.body.usernameEmail }, { email: req.body.usernameEmail }]})
if (!user) return res.status(400).send('Invalid username/email or password')
const validPassword = await bcrypt.compare(req.body.password, user.password)
if (!validPassword) return res.status(400).send('Invalid username/email or password')
const token = user.generateAuthToken()
res.send(token)
})
Does anybody know the issue here? Thanks.
I'm creating social network app with MERN. I have implemented followers and following, and now i'm trying to get the list of posts of only users that i'm following. So, if I console.log my req.user I only get the 'id' and 'iat', but i need more information of a user such as following array.
here is what i have:
auth.js middlware:
const config = require('config')
const jwt = require('jsonwebtoken')
function auth(req, res, next) {
const token = req.header('x-auth-token')
// check for token
if (!token) return res.status(401).json({ msg: 'Unauthorized token' })
try {
// verify token
const decoded = jwt.verify(token, config.get('jwtSecret'))
// add user from payload
req.user = decoded
console.log('---',decoded)
next()
} catch (e) {
return res.status(400).json({ msg: 'Token is not valid' })
}
}
module.exports = auth
auth.js
const express = require('express')
const router = express.Router()
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const config = require('config')
const User = require('../models/User')
const auth = require('../middleware/auth')
// #route POST /api/auth
// #desc Login user
// #access Public
router.post('/', (req, res) => {
const { email, password } = req.body
// filed validation
if (!email || !password) res.status(400).json({ msg: 'Fields cannot be empty.' })
// Check if user is registered
User
.findOne({ email })
.then(user => {
if (!user) res.status(400).json({ msg: `User doesn't exist.` })
//console.log(user)
// validate password
bcrypt
.compare(password, user.password)
.then(isMatch => {
if (!isMatch) return res.status(400).json({ msg: 'Invalid password' })
// if password matches, send token and user
jwt.sign(
{ id: user.id },
config.get('jwtSecret'),
(err, token) => {
if (err) throw err
res.json({
token,
user: {
id: user.id,
email: user.email,
first_name: user.first_name,
last_name: user.last_name,
registration_date: user.registration_date,
profile_image: user.profile_image,
user_bio: user. user_bio,
followers: user.followers,
following: user.following
}
})
}
)
})
})
})
and this is my console log
Server started at port 5000
[0] --- { id: '5efccfb13224e1489439bcfd', iat: 1593626545 }
[0] * { id: '5efccfb13224e1489439bcfd', iat: 1593626545 }
EDIT:
// #route GET /api/posts/subscribedPost
// #desc get all subscribed post
// #access Private
router.get('/subscribedPost', auth, (req, res) => {
console.log('*',req.user) // not working correctly, have only id and iat
Post
.find({userID: req.user.id})
.populate('userID', 'first_name last_name profile_image _id')
.sort({ registration_date: -1 })
.then(post => res.json(post))
.catch(err => res.json(err))
})
This is because you are signing your JWT token with id only, so when u decode it you will only get id
jwt.sign({ id: user.id },config.get('jwtSecret'),(err, token) =>{})
Here you are just passing id, you can pass your whole user object to get all the data
jwt.sign(user.toJSON(),config.get('jwtSecret'),(err, token) =>{})
PS- YOU MIGHT NOT WANT TO PASS YOUR WHOLE USER, JUST DID IT FOR DEMO
You can customize to what values you want.
You need to get user data DB in auth middleware and then add it to req.user. So if there are any changes to the user you get updated user data.
eg:
function auth(req, res, next) {
const token = req.header('x-auth-token')
// check for token
if (!token) return res.status(401).json({ msg: 'Unauthorized token' })
try {
// verify token
const decoded = jwt.verify(token, config.get('jwtSecret'))
// get the user from DB
const user = User.findById(decoded.id) //only populate fields which are required
req.user = user
console.log('---',decoded)
next()
} catch (e) {
return res.status(400).json({ msg: 'Token is not valid' })
}
}
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)
}
}