how to implement jwt verify token implement in node js.I already tried but its not showing error but its showing undefined.How to solve this issue.
auth.py
function jwtAccessAuthCheck(accessToken)
{
if(accessToken)
{
console.log("Sucess")
jwt.verify(accessToken,"secretkey",function(err){
if(err) {
console.log(typeof(err.message))
return err.message
}
else {
return "token"
}
});
}
else
{
return "Invalid token"
}
}
routes.py
//Get Data from Database
router.get('/', async (req, res,next) => {
(async function() {
try {
await client.connect();
console.log("Connected correctly to server");
const db = client.db('olc_prod_db');
const token_validation = validate_token.validate_token(req.headers.authorization)
console.log((token_validation))
const r = await db.collection('Ecommerce').find().toArray();
client.close();
res.send(r)
} catch(err) {
console.log(err.stack);
}
})();
});
const express = require('express');
const app = express();
const jwt = require('jsonwebtoken');
const bodyparser = require('body-parser');
const user = {username : "user",password : "pass"}
app.use(bodyparser.json());
const checkToken = function (req,res,next)
{
const header = req.headers['authorization'];
if(typeof header !== 'undefined')
{
const bearer = header.split(' ');
const token = bearer[1];
req.token=token;
next();
}
else
{
res.sendStatus(403);
}
}
app.post('/login',function (req,res)
{
const { body } = req;
const { username } = body;
const { password } = body;
if(username === user.username && password === user.password)
{
jwt.sign({user},'privatekey',{expiresIn : '1h'},function (err,token){
if(err)
{
console.log(err)
}
console.log(token);
res.end();
});
}
else
{
console.log('Error : Could not log in');
}
});
app.get('/data',checkToken,function(req,res)
{
jwt.verify(req.token,'privatekey',function (err,authorizedata)
{
if(err)
{
console.log('Error : Could not connect to the protected route');
res.sendStatus(403);
}
else
{
res.json({
message : 'Successful log in',
authorizedata
});
console.log('Success : Connected to protected route');
}
});
});
app.listen(3000,console.log("Server is running at 3000"));
This is how I have implemented JWT token
Related
When making the middleware request in my route, I always fall into the else of "verifyAdmin" (error 403). The big problem is that I can't send a throw or catch of this error, it just doesn't return any error in the terminal, but when testing in postman it always goes to else
const jwt = require('jsonwebtoken');
const verifyToken = (req, res, next) => {
const { authorization } = req.headers;
if (!authorization) {
return res.status(401).json('Invalid Authorization')
};
const token = authorization.replace('Bearer', ' ').trim();
try {
const secret = process.env.JWT_SECRET;
const data = jwt.verify(token, secret);
req.users = data;
const { id } = data;
req.userId = id;
return next();
} catch (err) {
return res.status(400).json(err);
}
};
const verifyAdmin = (req, res, next) => {
if (req.users.isAdmin === true) {
next();
} else {
return res.status(403).json("You are not alowed to do that!");
}
};
module.exports = {
verifyToken,
verifyAdmin,
};
in route
const { verifyToken, verifyAdmin } = require('../middlewares/verifyToken');
router.get('/', verifyToken, verifyAdmin, FindAllUsersController.index);
construction token
const db = require('../../models/index');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
exports.store = async (req, res) => {
const { email, password } = req.body;
const secret = process.env.JWT_SECRET;
try {
const user = await db.User.findOne({ where: { email } });
if (!user) {
return res.status(401).json('User does not exist');
}
const isValidPassword = await bcrypt.compare(password, user.password);
if (!isValidPassword) {
return res.status(401).json('Password is not valid');
}
const token = jwt.sign({ id: user.id }, secret, {
expiresIn: process.env.EXPIRES_TOKEN,
})
return res.status(200).json({
user,
token,
});
} catch (err) {
console.log(err);
}
}
The isAdmin flag is not contained in your token, because you include only the id when constructing it:
const token = jwt.sign({ id: user.id }, ...)
You need (at least):
const token = jwt.sign({ id: user.id, isAdmin: user.isAdmin }, ...)
Frontend Code
<script>
const formDOM = document.querySelector(".form");
const btnSubmitDOM = document.querySelector(".btn-submit");
// get token form server
formDOM.addEventListener("submit", async (e) => {
e.preventDefault();
const email = document.querySelector("#email").value;
const password = document.querySelector("#password").value;
try {
const { data } = await axios.post(
"http://localhost:3000/api/v1/auth/login",
{ email, password }
);
console.log("token", data.token);
localStorage.setItem("token", data.token);
} catch (error) {
console.log(error);
}
});
// after submit, if authenticated, goes to protective route
btnSubmitDOM.addEventListener("click", async () => {
const token = localStorage.getItem("token");
console.log("toekn when press", token);
try {
const { data } = await axios.get("http://localhost:3000/api/v1/inventories", {
headers: {
Authorization: `Bearer ${token}`,
},
});
location.assign("/inventories");
} catch (error) {
localStorage.removeItem("token");
console.log(error);
}
});
</script>
Here is the backend code
const jwt = require("jsonwebtoken");
const auth = async (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith("Bearer")) {
res.send("Auth route - Unauthenticated Error");
}
const token = authHeader.split(" ")[1];
console.log("token is ", token);
try {
const payload = jwt.verify(token, 'secret');
// console.log(payload);
// attached to the inventories route
req.user = {
userId: payload.userId,
email: payload.email,
};
// console.log(req.user)
next();
} catch (error) {
console.log(error);
}
};
module.exports = auth;
Here is the error from server side
token is eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MzY4ZjFiM2U1ODJlYmQ1MjJkODI4MGEiLCJlbWFpbCI6Imt5YXdAZ21haWwuY29tIiwiaWF0IjoxNjY3ODI3NzIzLCJleHAiOjE2NzA0MTk3MjN9.rptgRrYB4TrLQCxbB18JqMHd05LSox-LQuiLJS0L2Gw
/Users/kyawmyo/Desktop/software-development/nodejs-&-vanilajs-projects/inventories/middleware/authentication.js:8
const token = authHeader.split(" ")[1];
^
TypeError: Cannot read properties of undefined (reading 'split')
I try to test with postman, all working fine.
But I send request from client side, it is error, I cannot figure it out. Please help.
I have e problem in JWT with the express and react project. User add products and items page show product , Specific User see his added item not all item, I have use filter method.
Here is my API
app.get('/items', verifyJWT, async (req, res) => {
const decodedEmail = req.decoded.email;
const email = req.query.email;
if (email === decodedEmail) {
const query = { email: email };
const cursor = ItemsCollection.find(query);
const Items = await cursor.toArray();
res.send(Items);
}
else {
res.status(403).send({ message: 'forbidden access, Try again' })
}
})
my JWT function
function verifyJWT(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).send({ message: 'unauthorized access' });
}
const token = authHeader.split(' ')[1];
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, decoded) => {
if (err) {
return res.status(403).send({ message: 'Forbidden access, Please dont try' });
}
console.log('decoded', decoded);
req.decoded = decoded;
next();
})
}
My frontend react code is
const [user] = useAuthState(auth);
const [Items, setItems] = useState([]);
const navigate = useNavigate();
const [shouldRemount, setShouldRemount] = useState(false)
useEffect(() => {
const fetchData = async () => {
const email = user.email;
const url = `https://protected-tor-63915.herokuapp.com/items?email=${email}`;
try {
const response = await fetch(url)
if (response.status === 200) {
let data = await response.json();
setItems(data);
}
} catch (error) {
if (error.response.status === 401 || error.response.status === 403) {
signOut(auth);
navigate('/login')
}
}
}
fetchData();
}, [user, shouldRemount, navigate]);
I am using JWT token authentication in my Node.js and express application. But for each route I am calling the method to verify the token and my code is given below.
route.js:
const express = require('express'),
controller = require('../controller/customer.controller'),
verify = require('../utill/verify.util.js'),
Router = express.Router();
class DemoProjectRouter {
getRouter() {
try{
Router.get('/', verify.verifyToken, controller.getCustomer.bind(controller));
Router.post('/add',verify.verifyToken, controller.addCustomer.bind(controller));
return Router;
}catch(error) {
console.log(error);
}
}
}
module.exports = new DemoProjectRouter();
In the below file I am verifying the token.
const jwt = require('jsonwebtoken');
const _ = require('lodash');
const jwtKey = "my_secret_key"
const jwtExpirySeconds = '2d';
class DemoProjectJWT {
async createJWT(username) {
try{
let obj = {};
obj['username'] = username;
const token = jwt.sign(obj, jwtKey, {algorithm: "HS256", expiresIn: jwtExpirySeconds});
return token;
}catch(error){
console.log(error);
}
}
async verifyToken(req, res, next) {
try{
let token = '';
if (_.get(req,['body', 'token'])) {
token = req.body.token;
}
if (_.get(req,['query', 'token'])) {
token = req.query.token;
}
if (_.get(req,['headers', 'x-access-token'])) {
token = req.headers['x-access-token'];
}
if (_.get(req,['cookies', 'token'])) {
token = req.cookies.token;
}
if (token === '' || token === null) {
let err = new Error('No token provided!');
err.status = 403;
res.send(err);
}else{
jwt.verify(token, jwtKey, (err, decode) => {
if (err) {
if (err.name === 'TokenExpiredError') {
console.log("token expired!");
let err = new Error('You are not authenticated!');
err.status = 401;
res.send(err);
}
}else{
req.decoded = decode;
next();
}
})
}
}catch(error) {
console.log(error);
}
}
}
module.exports = new DemoProjectJWT();
Here I am binding my token in each route method but I need to write any common method where it will include the token in each route for verification so that if I am creating any new route method I will not add again verify.verifyToken for verification.for each user request it should call automatically.
You need to register your token verification handler as a router-level middleware:
Router.use(verify.verifyToken);
Router.get('/', controller.getCustomer.bind(controller));
Router.post('/add', controller.addCustomer.bind(controller));
You can do it with the app level middleware.
But make sure to put appropriate logic within that middleware, since it will get called for all the routes.
app.use('*', (req, res, next) => {
if (verify.verifyToken()) {
next();
} else {
// Do something else
}
})
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.