PUT method not allowed with http-proxy - node.js

When calling my PUT method, I got this error:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
</body>
</html>
I have some jwt authentification, so I put my complete code here:
It works with GET and POST methods
const express = require('express');
const logger = require('morgan');
var fs = require('fs');
var https = require('https');
var privateKey = fs.readFileSync('/etc/letsencrypt/live/hidden/privkey.pem', 'utf8');
var certificate = fs.readFileSync('/etc/letsencrypt/live/hidden/fullchain.pem', 'utf8');
const util = require('util')
var credentials = {key: privateKey, cert: certificate};
var queryString = require('querystring');
const bodyParser = require('body-parser');
const app = express();
const jwt = require('jsonwebtoken');
// import passport and passport-jwt modules
const passport = require('passport');
const passportJWT = require('passport-jwt');
const bcrypt = require('bcryptjs');
const Sequelize = require('sequelize');
var httpProxy = require('http-proxy');
var apiProxy = httpProxy.createProxyServer();
var backend = 'http://localhost:8484';
// initialize an instance of Sequelize
const sequelize = new Sequelize({
//hiden///
});
// ExtractJwt to help extract the token
let ExtractJwt = passportJWT.ExtractJwt;
// JwtStrategy which is the strategy for the authentication
let JwtStrategy = passportJWT.Strategy;
let jwtOptions = {};
jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
jwtOptions.secretOrKey = 'hidden';
// lets create our strategy for web token
let strategy = new JwtStrategy(jwtOptions, function(jwt_payload, next) {
console.log('payload received', jwt_payload);
let user = getUser({ id: jwt_payload.id });
if (user) {
next(null, user);
} else {
next(null, false);
}
});
// use the strategy
passport.use(strategy);
app.use(passport.initialize());
app.use(logger(':date[iso] :method :url :status :response-time ms - :res[content-length]'));
// parse application/json
app.use(bodyParser.json());
//parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
// check the databse connection
sequelize
.authenticate()
.then(() => console.log('Connection has been established successfully.'))
.catch(err => console.error('Unable to connect to the database:', err));
// create user model
const User = sequelize.define('user', {
name: {
type: Sequelize.STRING,
allowNull: false
},
code_event: {
type: Sequelize.INTEGER,
allowNull: false
},
password: {
type: Sequelize.STRING,
allowNull: false
},
});
// create table with user model
User.sync()
.then(() => console.log('User table created successfully'))
.catch(err => console.log('did you enter wrong database credentials?'));
// create some helper functions to work on the database
const createUser = async ({ name, password, code_event }) => {
try{
return await User.create({ name, password, code_event });
}
catch (error) {
// your catch block code goes here
}
};
const getAllUsers = async () => {
try{
return await User.findAll();
}
catch (error) {
// your catch block code goes here
}
};
const getUser = async obj => {
try{
return await User.findOne({where: obj,});
}
catch (error) {
// your catch block code goes here
}
};
// get all users
app.get('/users', function(req, res) {
getAllUsers().then(user => res.json(user));
});
// register route
app.post('/register', function(req, res, next) {
console.log(req.body);
let { name, password, code_event } = req.body;
bcrypt.genSalt(10, (err, salt) => {
if(err) throw err;
bcrypt.hash(password, salt,
(err, hash) => {
if(err) throw err;
password = hash;
createUser({ name, password, code_event }).then(user =>
res.json({ user, msg: 'account created successfully' })
)
.catch(err => res.status(400).json(err));
});
});
});
// login route
app.post('/login', async function(req, res, next) {
console.log(req.body);
const { name, password , code_event} = req.body;
if (name && password) {
// we get the user with the name and save the resolved promise returned
let user = await getUser({ name, code_event});
if (!user) {
res.status(401).json({ msg: 'No such user found', user });
}
bcrypt.compare(password, user.password)
.then(isMatch => {
if (isMatch) {
const payload = {id: user._id};
// let token = jwt.sign(payload, jwtOptions.secretOrKey, { expiresIn: 36000 }, (err, token) => {
// if (err) res.status(500).json({ error: "Error signing token", raw: err });
// res.json({ msg: 'ok', token: token });
// });
let token = jwt.sign(payload, jwtOptions.secretOrKey);
res.json({ msg: 'ok', token: token });
} else {
res.status(401).json("Password is incorrect");
}
});
}
});
apiProxy.on( 'proxyReq', ( proxyReq, req, res, options ) => {
console.log("body " +util.inspect(req.body, false, null, true /* enable colors */));
if ( !req.body || !Object.keys( req.body ).length ) {
return;
}
let contentType = proxyReq.getHeader( 'Content-Type' );
let bodyData;
if ( contentType.includes( 'application/json' ) ) {
bodyData = JSON.stringify( req.body );
}
if ( contentType.includes( 'application/x-www-form-urlencoded' ) ) {
bodyData = queryString.stringify( req.body );
}
if ( bodyData ) {
proxyReq.setHeader( 'Content-Length', Buffer.byteLength( bodyData ) );
proxyReq.write( bodyData );
}
});
app.all("/*", passport.authenticate('jwt', { session: false }), function(req, res) {
console.log("req all" + req);
apiProxy.web(req, res, {target: backend});
});
app.on('upgrade', function (req, socket, head) {
console.log("req on" + req);
apiProxy.ws(req, socket, head, {target: backend});
});
var httpsServer = https.createServer(credentials, app);
// start the app
httpsServer.listen(8383, function() {
console.log("Express is running on port 3000");
});
It works with my POST methods.
I don't know where it goes because, when calling a method, I should have a trace in my log files. I can see POST ot GET calls but not PUT ones.
Any ideas?

Related

Login Form Error nodejs express, how do i fix it?

this login form have some problem in it whenever I register and then login with credentials, it always show that my credentials are wrong.
this is auth.js code from controller
const mysql = require("mysql");
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const { promisify } = require('util');
const db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
});
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
if( !email || !password ) {
return res.status(400).render('login', {
message: 'Please provide an email and password'
})
}
db.query('SELECT * FROM users WHERE email = ?', [email], async (error, results) => {
console.log(results);
if( !results || !(await bcrypt.compare(password, results[0].password)) ) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
})
} else {
const id = results[0].id;
const token = jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN
});
console.log("The token is: " + token);
const cookieOptions = {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
),
httpOnly: true
}
res.cookie('jwt', token, cookieOptions );
res.status(200).redirect("/");
}
})
} catch (error) {
console.log(error);
}
}
exports.register = (req, res) => {
console.log(req.body);
const { name, email, password, passwordConfirm } = req.body;
db.query('SELECT email FROM users WHERE email = ?', [email], async (error, results) => {
if(error) {
console.log(error);
}
if( results.length > 0 ) {
return res.render('register', {
message: 'That email is already in use'
})
} else if( password !== passwordConfirm ) {
return res.render('register', {
message: 'Passwords do not match'
});
}
let hashedPassword = await bcrypt.hash(password, 8);
console.log(hashedPassword);
db.query('INSERT INTO users SET ?', {name: name, email: email, password: hashedPassword }, (error, results) => {
if(error) {
console.log(error);
} else {
console.log(results);
return res.render('register', {
message: 'User registered'
});
}
})
});
}
exports.isLoggedIn = async (req, res, next) => {
// console.log(req.cookies);
if( req.cookies.jwt) {
try {
//1) verify the token
const decoded = await promisify(jwt.verify)(req.cookies.jwt,
process.env.JWT_SECRET
);
console.log(decoded);
//2) Check if the user still exists
db.query('SELECT * FROM users WHERE id = ?', [decoded.id], (error, result) => {
console.log(result);
if(!result) {
return next();
}
req.user = result[0];
console.log("user is")
console.log(req.user);
return next();
});
} catch (error) {
console.log(error);
return next();
}
} else {
next();
}
}
exports.logout = async (req, res) => {
res.cookie('jwt', 'logout', {
expires: new Date(Date.now() + 2*1000),
httpOnly: true
});
res.status(200).redirect('/');
}
and this is app.js
const express = require("express");
const path = require('path');
const mysql = require("mysql");
const dotenv = require('dotenv');
const cookieParser = require('cookie-parser');
dotenv.config({ path: './.env'});
const app = express();
const db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
});
const publicDirectory = path.join(__dirname, './public');
app.use(express.static(publicDirectory));
// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded({ extended: false }));
// Parse JSON bodies (as sent by API clients)
app.use(express.json());
app.use(cookieParser());
app.set('view engine', 'hbs');
db.connect( (error) => {
if(error) {
console.log(error)
} else {
console.log("MYSQL Connected...")
}
})
//Define Routes
app.use('/', require('./routes/pages'));
app.use('/auth', require('./routes/auth'));
app.listen(5001, () => {
console.log("Server started on Port 5001");
})
When entered right credentials
enter image description here
whenever i enter credential whether right or wrong it shows this only.
please help me, i am stuck here
I am not sure but I think the problem is in controller/auth.js code and i tried to change the login code in that
Replace question mark with ${email}
'SELECT * FROM users WHERE email =${email}'

Client doesnt get cookie from my node.js api

I have made an authentication with jwt api in node.js/express and i run it on heroku.
When a user logged in, server create a cookie via cookie-parser and send it to the client.
Below is the code from server.js
const express = require('express');
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const cors = require('cors');
const path = require('path');
const bcrypt = require('bcrypt');
const PORT = process.env.PORT || 3000;
const serveStatic = require('serve-static');
require('dotenv').config();
const mongoose = require('mongoose');
const { User, Posts } = require(path.join(__dirname, './model.js'));
const mongoString = process.env.DATABASE_URL;
const JWT_SECRET = process.env.JWT_SECRET;
const { verifyToken, checkUser } = require(path.join(__dirname, './auth.js'));
const app = express();
//Middlewares
app.use(
cors({
credentials: true,
origin: true,
})
);
app.use(express.json());
app.use(cookieParser());
//Connect to Database
mongoose.connect(mongoString);
const db = mongoose.connection;
db.on('error', (err) => {
console.log(err);
});
db.once('connected', () => {
console.log('----Database Connected----\n');
});
//functions
const maxAge = 3 * 24 * 60 * 60;
const createToken = (id) => {
return jwt.sign({ id }, JWT_SECRET, {
expiresIn: maxAge,
});
};
// AUTH ROUTES
app.get('*', checkUser);
app.get('/', checkUser, (req, res) => {
res.json({ status: 'success' });
});
app.post('/api/register', async (req, res) => {
const salt = await bcrypt.genSalt();
try {
const user = await User.create(
new User({
username: req.body.username,
email: req.body.email,
city: req.body.city,
password: await bcrypt.hash(req.body.password, salt),
})
);
const token = createToken(user._id);
res.cookie('jwt', token, {
maxAge: maxAge * 1000,
secure: true,
});
res.status(201).json(user);
console.log(user);
} catch (err) {
console.log(err);
res.json(err);
}
});
app.post('/api/login', async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email }).lean();
if (!user) {
return res.send({
status: 'error',
error: 'Invalid email',
});
}
if (await bcrypt.compare(password, user.password)) {
const token = createToken(user._id);
res.cookie('jwt', token, { secure: true, maxAge: maxAge * 1000 });
res.status(200).send({ status: 'ok', token: token });
console.log(user._id + ' logged in successfully');
return;
}
return res.send({ status: 'error', error: 'Invalid password' });
} catch (err) {
console.log(err);
}
});
app.get('/api/home', verifyToken, (req, res) => {
res.send(res.locals.user);
});
app.get('/api/logout', (req, res) => {
try {
res.cookie('jwt', '', { maxAge: 1 });
res.status(200).send({ status: 'ok' });
} catch (err) {
res.send(err);
}
});
//POSTS ROUTES
app.post('/api/posts', verifyToken, checkUser, async (req, res) => {
try {
const post = await Posts.create(
new Posts({
postBody: req.body.postBody,
city: req.body.city,
author: res.locals.user.id,
})
);
res.status(200).json(post);
console.log('====New Post=====');
} catch (err) {
res.status(400).send({ message: err.message });
}
});
app.get('/api/posts', verifyToken, async (req, res) => {
try {
const data = await Posts.find();
res.send({ user: res.locals.user, data: data });
} catch (err) {
res.json({ message: err.message });
}
});
app.get('/api/posts/:city', verifyToken, async (req, res) => {
try {
const data = await Posts.find({ city: req.params.city });
res.json(data);
res.send(res.locals.user);
} catch (err) {
res.json({ message: err.message });
}
});
//run server
app.listen(PORT, () => {
console.log(`Server running on ${PORT}...\n`);
});
Now, for front-end i use Vue.js that its running on Firebase.
Here is the script part of Login.Vue
<script>
/* eslint-disable */
import axios from 'axios';
export default {
name: 'Login',
data() {
return {
email: '',
password: '',
error: '',
};
},
methods: {
async onSubmit() {
if (!this.email || this.password.length < 6) {
this.error = 'vale kati';
return;
}
await axios
.post(
'https://thelostpet.herokuapp.com/api/login',
{
email: this.email,
password: this.password,
},
{ withCredentials: true }
)
.then((res) => {
console.log(res.data.token);
if (res.data.status == 'error') {
this.error = res.data.error;
}
if (res.data.status == 'ok') {
this.$router.push('/home');
}
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
When I try to login from Login.vue, that its ruuning on Firebase, the browser doesn't save the cookie that it created from the api.
BUT when I make a post request on https://thelostpet.herokuapp.com/api/login from postman, the cookie is saved on postman.
Thank you!

I am getting 404 error and 204 error when consuming backend (node,vuejs)?

When signing in with postman everything works fine. But when i am doing an axios request i get 404 error and directly after 204 error. When i render my vue.js page i get "cannot get api/auth/signin. Also I get a message somewhere that says user not found.
What i have tried:
Frontend: I tried with adding headers to my axios request. I console logged the data and it seems perfectly fine.
Backend: Changed deprecated body parsers.
Frontend Code:
Auth store
import axios from "axios";
const state = {
token: "",
users: [],
};
const getters = {};
const actions = {
async signIn(_, payload) {
const response = await axios.post(
"http://localhost:3000/api/auth/signin",
{ payload },
{
headers: {
"Content-Type": "application/json",
},
}
);
console.log(response.data);
console.log(response.headers);
console.log(response.status);
},
};
const mutations = {};
export default {
state,
getters,
actions,
mutations,
};
This is my backend:
Controller
//signin
exports.signin = (req, res) => {
User.findOne({
username: req.body.username,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
var 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
});
var authorities = [];
for (let i = 0; i < user.roles.length; i++) {
authorities.push("ROLE_" + user.roles[i].name.toUpperCase());
}
res.status(200).send({
id: user._id,
username: user.username,
email: user.email,
roles: authorities,
accessToken: token,
});
});
};
Route
module.exports = function (app) {
app.use(function (req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"x-access-token, Origin, Content-Type, Accept"
);
next();
});
app.post(
"/api/auth/signup",
[
verifySignUp.checkDuplicateUsernameOrEmail,
verifySignUp.checkRolesExisted,
],
controller.signup
);
app.post("/api/auth/signin", controller.signin);
And my server
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const jwt = require("jsonwebtoken");
const mongoose = require("mongoose");
const Quote = require("./models/Quote");
const quoteRoute = require("./routes/quoteRoute");
const quoteController = require("../Maxico/controllers/quoteController");
const config = require("./config/config");
const verifySignup = require("./middlewares/verifySignUp");
const Role = require("./models/Role");
const app = express();
//Import routes
//const authRoute = require("./routes/auth");
var corsOptions = {
origin: "http://localhost:8080/?#/",
};
app.use(cors(corsOptions));
app.use(express.urlencoded({ extended: true }));
app.use(express.json()); //
const db = require("./models/Quote");
mongoose
.connect(
"url",
{
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
}
)
.then(() => {
console.log("Connected to the database!");
})
.catch((err) => {
console.log("Cannot connect to the database!", err);
process.exit();
});
app.use(express.json());
app.get("/", (req, res) => {
res.send("Welcome to homepage");
});
app.use("/quote", quoteRoute);
require("./routes/authRoute")(app);
//require("./routes/userRoute")(app);
// initial roles
Role.estimatedDocumentCount((err, count) => {
if (!err && count === 0) {
new Role({
name: "user",
}).save((err) => {
if (err) {
console.log("error", err);
}
console.log("added 'user' to roles collection");
});
new Role({
name: "moderator",
}).save((err) => {
if (err) {
console.log("error", err);
}
console.log("added 'moderator' to roles collection");
});
new Role({
name: "admin",
}).save((err) => {
if (err) {
console.log("error", err);
}
console.log("added 'admin' to roles collection");
});
new Role({
name: "superadmin",
}).save((err) => {
if (err) {
console.log("error", err);
}
console.log("added 'superadmin' to roles collection");
});
}
});
// set port, listen for requests
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
In my network tab the request pay load got sent like this:
{payload: {username: "jon", password: "password"}}
payload: {username: "jon", password: "password"}
But my postman only accepts this:
{username: "jon", password: "password"}
So in my action i sent like this:
const actions = {
async signIn(_, payload) {
console.log(payload);
const response = await axios.post(
"http://localhost:3000/api/auth/signin",
payload,
{
headers: {
"Content-Type": "application/json",
},
}
);
console.log(payload);
console.log(response.data);
console.log(response.headers);
console.log(response.status);
},
};

Where did I go wrong with passport-jwt setup?

I tried to add passport-jwt to my MEVN-stack application, login is successful, but when app tries to redirect to home page after login, I get 401 Unauthorized error in console. I pass token as value of Authorization header in get request on the home page, but it did not help.
This is the code of server.js (the entrypoint of server side):
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const cors = require('cors');
const morgan = require('morgan');
const fs = require('fs');
const jwt = require('jsonwebtoken');
const passport = require('passport');
const passportJWT = require('passport-jwt');
const ExtractJWT = passportJWT.ExtractJwt;
const JWTStrategy = passportJWT.Strategy;
const jwtOptions = {};
jwtOptions.jwtFromRequest = ExtractJWT.fromAuthHeaderWithScheme('jwt');
jwtOptions.secretOrKey = 'movieratingapplicationsecretkey';
const app = express();
const router = express.Router();
const User = require('./models/User');
app.use(morgan('combined'));
app.use(bodyParser.json());
app.use(cors());
app.use(passport.initialize());
passport.use(new JWTStrategy(jwtOptions, (jwt_payload, done) => {
User.findOne({ id: jwt_payload.id }, (err, user) => {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
}));
mongoose.connect('mongodb://localhost/movie_rating_app', {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log('Connection is established');
})
.catch((err) => {
console.error(`App starting error: ${err.stack}`);
});
// include controllers
fs.readdirSync('controllers').forEach(file => {
if (file.substr(-3) === '.js') {
const route = require(`./controllers/${file}`)
route.controller(app)
}
})
router.get('/', (req, res) => {
res.json({ message: 'API was initialized!' });
});
const port = process.env.API_PORT || 8081;
app.use('/', router);
app.listen(port, () => {
console.log(`api running on port ${port}`);
});
This is the movies.js controllerm, which contains passport.authenticate() method in get request:
const Movie = require('../models/Movie')
const Rating = require('../models/Rating')
const passport = require('passport')
module.exports.controller = app => {
// fetch all movies
app.get(
'/movies',
passport.authenticate('jwt', { session: false }),
(req, res) => {
Movie.find({}, 'name description release_year genre', (error, movies) => {
if (error) console.error(error)
res.send(movies);
})
})
// fetch a single movie
app.get('/movies/:id', (req, res) => {
Movie.findById(req.params.id, 'name description release_year genre', (error, movie) => {
if (error) console.error(error)
res.send(movie);
})
})
}
This is the users.js controller:
const User = require('../models/User');
const passportJWT = require('passport-jwt');
const jwt = require('jsonwebtoken');
const ExtractJwt = passportJWT.ExtractJwt;
const jwtOptions = {};
jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('jwt');
jwtOptions.secretOrKey = 'thisisthesecretkey';
module.exports.controller = app => {
// register a user
app.post('/users/register', (req, res) => {
const newUser = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password,
})
User.createUser(newUser, (error, user) => {
if (error) {
res.status(422).json({
message: 'Something went wrong. Please try again after some time'
})
}
res.send({ user });
})
})
// login user
app.post('/users/login', (req, res) => {
if (req.body.email && req.body.password) {
const email = req.body.email,
password = req.body.password;
User.getUserByEmail(email, (err, user) => {
if (!user) {
res.status(404).json({ message: 'The user does not exist' })
} else {
User.comparePassword(password, user.password, (error, isMatch) => {
if (error) throw error;
if (isMatch) {
const payload = { id: user.id };
const token = jwt.sign(payload, jwtOptions.secretOrKey);
res.json({ message: 'ok', token })
} else {
res.status(401).json({ message: 'The password is incorrect' })
}
})
}
})
}
})
}
This is the script part of Home.vue, when I try to receive response:
<script>
import axios from 'axios';
import MovieCard from '#/components/MovieCard.vue';
export default {
name: 'Home',
components: {
MovieCard,
},
data: () => ({
movies: [],
}),
mounted() {
this.fetchMovies();
},
methods: {
async fetchMovies() {
const token = window.localStorage.getItem('auth');
return axios({
method: 'get',
url: 'http://localhost:8081/movies',
headers: {
Authorization: `JWT ${token}`,
'Content-Type': 'application/json',
},
})
.then((response) => {
console.log(response);
});
// return axios.get('http://localhost:8081/movies')
// .then(({ data }) => {
// this.movies = data;
// })
// .catch((error) => {
// console.error(error);
// });
},
},
};
</script>
Please don't mark my question as duplicate, because I have already tried some advices such as change ExtractJWT.fromAuthHeaderWithScheme('jwt') to ExtractJWT.fromAuthHeaderWithScheme('bearer'), but it did not help me.
How to fix 401 error?
I replaced all ExtractJwt.fromAuthHeaderWithScheme('jwt') with ExtractJwt.fromAuthHeaderAsBearerToken(), and set all jwtOptions.secretOrKey values as 'thisisthesecretkey'. 401 error does not exist now

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.

Resources