I’m trying to build an authentication with passport and jsonwetoken in node.js & express in my backend.
When my user is logged in, a token is given to his connexion for 1h.
I have created a getOneUser function which allow an user to get his own information, or if the user is an admin.
My function is working but I would like to implement the « jwt.verify » method inside to check if the token if still valid, and therefore use its response to automatically redirect an user with an invalid token to my loginPage in my React frontend.
I have and idea of what and where to place my elements but I’am always getting the « Unauthorized » message in Postman without never have my pre-written error message. I have no idea if my thinking is correct because there is no console.log that is showing after the token expiration’s time.
I have tried many solutions available on stackOverflow but I can’t seem to overthrow this « Unauthorized » message which I suppose come from passport because my token is expired.
Message that I would like to change or be accompanied with my own error message in order to redirect later in my frontend.
I tried to create a token verify function on its own and my coding is working just fine, but I can’t seem to make it works with passport and implement it to my getOneUser function.
Could you please give some advice ?
Thank you in advance for your help !
My main leads to help me but without success :
Here is my passport method :
const passport = require("passport");
const passportJwt = require("passport-jwt");
const ExtractJwt = passportJwt.ExtractJwt;
const StrategyJwt = passportJwt.Strategy;
const { AuthUser } = require("../../models/Index");
const User = AuthUser;
//Implementation of the passport strategy with jwt
passport.use(
new StrategyJwt(
{
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_ACCESS_TOKEN_SECRET,
passReqToCallback: true
},
function (req, jwtPayload, done) {
return User.findOne({ where: { id_auth_user: jwtPayload.userId } })
.then((user) => {
if(!user) {
return done({error : 'error'}, false);
}
req.user = user;
return done(null, user);
})
.catch((err) => {
console.log("err", err);
return done(err);
});
}
)
);
My login function which is generating a token to a user’s connexion :
exports.login = async (req, res, next) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ where: { email: email } });
if (!user) {
res.status(400).json({ message: "Incorrect login details ! Please, try again." });
}
if (await bcrypt.compare(password, user.password)) {
const token = jwt.sign(
{
userId: user.id_auth_user,
email: user.email,
userFirstName: user.firstname
},
process.env.JWT_ACCESS_TOKEN_SECRET,
{
expiresIn: "1h",
}
);
if (res.status(201)) {
return res.json({
status: "success",
token: token,
userId: user.id_auth_user.toString(),
values: user,
});
} else {
return res.json({
error: "error",
});
}
}
res.status(400).json({ status: "error", message: "Incorrect login details ! Please, try again." });
} catch (error) {
console.log(error);
}
};
My getOneUser function which allow a user to get his own informations :
exports.getOneUser = async (req, res, next) => {
const query = req.params.id_auth_user;
const userId = req.user.id_auth_user.toString();
const token = req.headers.authorization.split(" ")[1];
try {
/* Where I try to implement the verification of my token */
const user = jwt.verify(token, process.env.JWT_ACCESS_TOKEN_SECRET, (err, res) => {
if (err) {
return "token is expired";
}
console.log("token is valid");
return res;
});
console.log(user);
/* this console.log is showing me the token's informations ONLY when the token is still valid, but nothing and it's invalid...
/* Passport keeps sending "Unauthorized" in Postman when token is invalid.
if (user == "token is expired") {
return res.send({ status: "error", data: "token is expired" });
}
if (query === userId || req.user.role === "admin") {
User.findOne({ where: { id_auth_user: query } })
.then((user) => {
if (!user) {
const error = new Error("User doesn't exist. Please try again.");
error.statusCode = 404;
throw error;
}
res.status(200).json({ user: user, token: token });
})
.catch((err) => {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
} else {
res.json({ error: "You don't have the permission to modify this profile" });
}
} catch (error) {
console.log("error", error);
throw error;
}
};
My routes :
const router = express.Router();
const UserController = require('../../controllers/AuthUser/UserController')
const passport = require("passport");
//User connexion
router.post("/login", UserController.login);
//User & Admin
//A user can get his own informations or is an Admin
router.get("/users/:id_auth_user", passport.authenticate("jwt", { session: false }), UserController.getOneUser);
My lastest try was to create a separate token verification which is working if I remove the “passport.authenticate” part :
exports.verifyToken = (req, res) => {
const token = req.headers.authorization.split(" ")[1];
const user = jwt.verify(token, process.env.JWT_ACCESS_TOKEN_SECRET, (err, res) => {
if (err) {
return "token is expired";
}
console.log("token is valid");
return res;
});
console.log(user);
if (user == "token is expired") {
return res.send({ status: "error", data: "token is expired" });
}
};
router.post("/token", UserController.verifyToken);