express-jwt secret should be set error when secret is set - node.js

In my web app, I'm using express-jwt, but for some reason the secret refuses to be loaded and i do not understand why.
const express = require('express')
import { createClient } from "redis"
import { UserApi } from "./api/users"
const jwtExpress = require('express-jwt')
(async () => {
//load in dotenv
require('dotenv').config()
const app = express()
const client = createClient()
//Check redis
client.on('error', (err) => console.log('Redis Client Error', err))
//Connect to redis client
await client.connect()
//Create API instances
const ua = new UserApi(client)
//Initialize middleware
app.use(express.json())
app.use(jwtExpress({ secret: "test", algorithms: ['HS256']}).unless({path: ['/token', '/test']}));
//Create routes
//test
app.get("/test", function(req, res) {
res.send("got")
})
//signup - creates user
app.post("/signup", async function(req, res) {
const u = {email: req.body.email, password: req.body.password}
try {
const {token, refreshToken} = await ua.create(u)
res.send({token: token, refreshToken: refreshToken, user_email: u.email })
} catch (error) {
res.status(400).send({error: error.toString()})
}
})
//login - logs in user
app.post("/login", async function(req, res) {
const u = {email: req.body.email, password: req.body.password}
try {
const token = await ua.login(u)
res.send(token)
} catch (error) {
res.status(400).send({error: error.toString()})
}
})
//refresh - refreshes token
app.post('/refresh', async function (req, res) {
const u = {email: req.body.email, refresh: req.body.refreshToken}
try {
const token = await ua.token(u.email, u.refresh)
res.send(token)
} catch (error) {
res.status(400).send({error: error.toString()})
}
})
app.listen(3000, () => {
console.log("server up")
})
}) ()
Could the async function be a problem? This is a copy of the error I receive:
if (!options || !options.secret) throw new Error('secret should be set');
^
Error: secret should be set
at module.exports (C:\Users\user\Projects\music-app\backend\node_modules\express-jwt\lib\index.js:20:42)

Related

Why is req.cookie.token_name not working?

I was building authentication for a website
and the req.cookie was returning undefined. Can I know what's wrong with that?
this is my server code
and I imported the auth file here
app.get("/", auth, (req, res) => {
res.render("index")
})
this is my auth.js file
const jwt = require("jsonwebtoken")
const Register = require("../models/registration")
const cookieParser = require("cookie-parser")
const express = require("express")
const app = express()
app.use(cookieParser())
const auth = async (req, res, next) => {
try {
const token = req.cookie.token_name
console.log(token)
const verifyUser = jwt.verify(token, process.env.SECRET_KEY)
next()
} catch (error) {
console.log(error)
res.status(401).send(error)
}
}
module.exports = auth
if required this is my login code as well but yeah i verified its storing cookies on the browser
app.post("/login", async (req, res) => {
try {
const password = req.body.password
const email = req.body.email
const user = await Register.findOne({ email: email })
const isMatch = await bcrypt.compare(password, user.password)
const token = await user.generateAuthenticationToken()
res.cookie('jwt', token, {
maxAge: 600*1000,
httpOnly: true,
})
if (isMatch) {
res.redirect("/")
} else {
res.send("Invalid Credentials")
}
} catch (error) {
res.status(404).send(error)
}
})

Node.js Canno't GET or POST users from route

I am doing backend login and register project with Nodejs and Express but somehow I cannot login or register anymore or even fetch data from my usersRoute and I don't know why. I am lost..
My index.ts file:
import express from "express";
const https = require("https");
import cors from "cors";
import mongoose from "mongoose";
const app = express();
//import Routes
const usersRoute = require("./routes/users");
//Middleware
app.use(cors());
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
//Route middlewares
app.use("api/users", usersRoute);
//connect to db
mongoose
.connect("mongodb://localhost:27017/containerlab")
.then(() => {
console.log("connected to database");
})
.catch(() => {
console.log("connection failed!");
});
const PORT = 5000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
My users.ts file
import express from "express";
const router = express.Router();
const User = require("../models/User");
const {
registerValidation,
loginValidation,
} = require("../middleware/validation");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const secretKey = "f43g34gergeerg";
const verifyToken = require("../middleware/verifyToken");
//REGISTER user
router.post("/register", async (req, res) => {
//VALIDATE DATA from Joi, before register
const { error } = registerValidation(req.body);
if (error) return res.status(400).send(error.details[0].message);
//check if user is alredy in database
const emailExist = await User.findOne({ email: req.body.email });
if (emailExist) return res.status(400).send("Email already exists");
//encrypt password z bcryptjs modulom
const salt = await bcrypt.genSalt(10);
const hashPassword = await bcrypt.hash(req.body.password, salt);
//create new user
const user = new User({
email: req.body.email,
password: hashPassword,
});
try {
//save new user
const savedUser = await user.save();
//res.json(savedUser);
res.json({ user: user._id });
} catch (err) {
res.json({ message: err });
}
});
//LOGIN
router.post("/login", async (req, res) => {
//VALIDATE DATA from Joi, before register
const { error } = loginValidation(req.body);
if (error) return res.status(400).send(error.details[0].message);
//check if email exists.. če NE obstaja mail dobiš da ne ustreza
const user = await User.findOne({ email: req.body.email });
if (!user) return res.status(400).send("Email doesn't exist");
const validPass = await bcrypt.compare(req.body.password, user.password);
if (!validPass) return res.status(400).send("Invalid password");
//create and send a json web token
const token = jwt.sign({ _id: user._id }, secretKey, { expiresIn: "1h" });
res.header("auth-token", token).send(token);
res.send("Logged in!");
});
//get users
router.get("/", async (req, res) => {
try {
const users = await User.find();
res.json(users);
} catch (err) {
res.json({ message: err });
}
});
module.exports = router;
And my verifyToken.ts middleware
const jwt = require("jsonwebtoken");
const secretKey = "f43g34gergeerg";
module.exports = (req: any, res: any, next: any) => {
const token = req.header("auth-token");
if (!token) return res.status(401).send("Access denied");
try {
const verified = jwt.verify(token, secretKey);
req.user = verified;
next();
} catch (err) {
res.status(400).send("Invalid token");
}
};
Somehow I can't fetch ANY data from users.ts (from usersRoute). Thank you for your help

losing session on refresh NodeJs

I am following a tutorial on Udemy and creating a react app using node and express. I am losing my session and being sent back to the login page on refresh. The instructors app stays in session on refresh. Could bad routing be causing this issue? I'll provide auth.js file from my routing folder. I can add more if needed.
<<< SERVER.JS file >>>
const express = require('express');
const connectDB = require('./config/db');
const app = express();
// CONNECT To Database
connectDB();
// Init Middleware
app.use(express.json({extended: false}))
app.get('/', (req, res) => res.send('Well, hello there!'));
app.use('/api/posts', require('./routes/api/posts'));
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`server is listening on port ${PORT}`));
<<< middleware >>>
const jwt = require('jsonwebtoken');
const config = require('config');
module.exports = function(req, res, next) {
// Get token from header
const token = req.header('x-auth-token');
// Check if not token
if (!token) {
return res.status(401).json({ msg: 'No token, authorization denied' });
}
// Verify token
try {
const decoded = jwt.verify(token, config.get('jwtSecret'));
req.user = decoded.user;
next();
} catch (err) {
res.status(401).json({ msg: 'Token is not valid' });
}
};
just in case my here is my auth.js file from routing folder
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const auth = require('../../middleware/auth');
const jwt = require('jsonwebtoken');
const config = require('config');
const { check, validationResult } = require('express-validator');
const User = require('../../models/User');
// #route GET api/auth
// #desc Test route
// #access Public
router.get('/', auth, async (req, res) => {
try {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
// #route POST api/auth
// #desc Authenticate user & get token
// #access Public
router.post(
'/',
[
check('email', 'Please include a valid email').isEmail(),
check('password', 'Password is required').exists()
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email, password } = req.body;
try {
let user = await User.findOne({ email });
if (!user) {
return res
.status(400)
.json({ errors: [{ msg: 'Invalid Credentials' }] });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res
.status(400)
.json({ errors: [{ msg: 'Invalid Credentials' }] });
}
const payload = {
user: {
id: user.id
}
};
jwt.sign(
payload,
config.get('jwtSecret'),
{ expiresIn: 360000 },
(err, token) => {
if (err) throw err;
res.json({ token });
}
);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
}
);
module.exports = router;

Why am I getting a 401 Unauthorized Error when hitting my protected endpoint at /api/protected?

I am using JWT to generate a token for access control. I can hit /api/auth/login and get back the token, however, when attempting to hit /api/protected with a GET request, I get 401 Unauthorized.
I've looked through SO and haven't found anything specific although it seems like a routine issue, maybe. I have tried moving the route around in the server.js file to see if that is the issue . I have removed the preceeding slash from the route (from /api/protected to api/protected) and using the latter I get back a bunch of html due to, I think, the app.use(express.static....
I am using Postman to test it but i'm not sure what I'm missing here. I have also made sure to set the authorization to Bearer Token in Postman.
'use strict';
const { Strategy: LocalStrategy } = require('passport-local');
// Assigns the Strategy export to the name JwtStrategy using object destructuring
const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt');
const { User } = require('../users/models');
const { JWT_SECRET } = require('../config');
const localStrategy = new LocalStrategy((username, password, callback) => {
let user;
User.findOne({ username })
.then(_user => {
user = _user;
if (!user) {
// Return a rejected promise so we break out of the chain of .thens.
// Any errors like this will be handled in the catch block.
return Promise.reject({
reason: 'LoginError',
message: 'Incorrect username or password'
});
}
return user.validatePassword(password);
})
.then(isValid => {
if (!isValid) {
return Promise.reject({
reason: 'LoginError',
message: 'Incorrect username or password'
});
}
return callback(null, user);
})
.catch(err => {
if (err.reason === 'LoginError') {
return callback(null, false, err);
}
return callback(err, false);
});
});
const jwtStrategy = new JwtStrategy(
{
secretOrKey: JWT_SECRET,
// Look for the JWT as a Bearer auth header
jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
// Only allow HS256 tokens - the same as the ones we issue
algorithms: ['HS256']
},
(payload, done) => {
done(null, payload.user);
}
);
module.exports = { localStrategy, jwtStrategy };
'use strict';
//How does order of code affect how it works?
// YES
require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const morgan = require('morgan');
const passport = require('passport');
const path = require('path');
const { router: usersRouter } = require('./users');
const { router: authRouter, localStrategy, jwtStrategy } = require('./auth');
mongoose.Promise = global.Promise;
// Is this needed if dotenv is in this file also?
const { PORT, DATABASE_URL } = require('./config');
const app = express();
// Logging
app.use(morgan("common"));
// const logRequest = (req, res, next) => {
// const now = new Date();
// console.log(
// `local log - ${now.toLocaleDateString()} ${now.toLocaleTimeString()} ${req.method} ${req.url}`
// );
// next();
// }
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE');
if (req.method === 'OPTIONS') {
return res.send(204);
}
next();
});
passport.use(localStrategy);
passport.use(jwtStrategy);
//app.use(logRequest);
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use('/api/users/', usersRouter);
app.use('/api/auth/', authRouter);
app.use("/api/items", require('./routes/api/items'));
// protected route that needs a valid JWT for access
const jwtAuth = passport.authenticate("jwt", { session: false });
// route to handle static content ie.e *.jpg
app.use(express.static(path.join(__dirname, "client", "build")));
app.get('/api/protected', jwtAuth, (req, res) => {
return res.json({
data: 'Hello World'
});
});
// have react client handle all additional routes
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "client", "build", "index.html"));
});
let server;
function runServer(DATABASE_URL, port = PORT) {
return new Promise((resolve, reject) => {
// How is DATABASE_URL used? What is the value? Is it referencing
// DATABASE_URL?
mongoose.connect(DATABASE_URL, { useNewUrlParser: true, useFindAndModify: false }, (err) => {
console.log("Success");
if (err) {
return reject(err);
}
server = app.listen(port, () => {
console.log(`Your app is listening on port ${PORT}`);
resolve();
})
.on('error', (err) => {
mongoose.disconnect();
reject(err);
});
});
});
}
function closeServer() {
return mongoose.disconnect()
.then(() => new Promise((resolve, reject) => {
console.log("Closing server");
server.close((err) => {
if (err) {
return reject(err);
}
resolve();
});
}));
}
if (require.main === module) {
runServer(DATABASE_URL)
.catch(err => console.error(err));
}
module.exports = { app, runServer, closeServer };
enter code hereI am expecting to get back a string that says "Hello World" just to make sure i'm hitting the endpoint correctly. Instead I get the 401 error, GET /api/protected HTTP/1.1" 401enter code here

Uncaught AssertionError: expected {} to equal 'testing'

I'm not sure why it's saying the object is empty. This is my testing block of code.
describe("POST /users", () => {
let body = {
name: "testing",
email: "testing#testing.com",
password: 123456
};
it("Creates a new user", done => {
request(app)
.post("/register")
.send(body)
.end((err, res) => {
if (err) return done(err);
expect(res.body).to.be.equal("testing");
done();
});
});
});
Is there something I'm missing for the test to recognize the information being passed in? As in the payload since I thought that is what .send(payload) was for.
Thanks for the clarity.
** Update Controller and more information **
// Testing
let request = require("supertest");
let expect = require("chai").expect;
let app = require("../../server/server");
describe("GET /test", function() {
it("Returns a json for testing", done => {
request(app)
.get("/test")
.end((err, res) => {
done();
});
});
});
describe("POST /users", () => {
let body = {
name: "testing",
email: "testing#testing.com",
password: 123456
};
it("Creates a new user", done => {
request(app)
.post("/register")
.send(body)
.expect(res => {
expect(res.body).to.be.equal("testing");
})
.end(done);
});
});
// User routes
const express = require("express");
const router = express.Router();
// Load User Model
const User = require("../../models/User");
// #route GET api/users/test
// #desc Tests user route
// #access Public
router.get("/test", (req, res) => res.json({ msg: "Users Works" }));
router.post("/register", (req, res) => {
User.findOne({ email: req.body.email }).then(user => {
if (user) {
res.status(409).json({ msg: "User exist" });
} else {
const newUser = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password
});
newUser
.save()
.then(user => res.status(200).send(user))
.catch(err => console.log(err));
}
});
});
module.exports = router;
// Server
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
const users = require("./routes/api/users");
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// DB Config
const db = require("../config/keys").mongoURI;
// Connect to MongoDB Atlas
mongoose.connect(
db,
{ useNewUrlParser: true },
(err, client) => {
if (err) {
console.log("Error occurred while connecting to MongoDB Atlas...\n", err);
}
console.log("Connected...");
}
);
// Routes
app.use("/api/users", users);
const port = process.env.PORT || 5000;
let server = app.listen(port, () =>
console.log(`Server running on port ${port}`)
);
module.exports = server;

Resources