This is my index.js
import express from "express";
import router from "./routes/routes.js";
import connectDB from "./db.js";
const app = express();
connectDB();
app.use(express.json());
app.use("/", router);
app.listen(3000, () => console.log("server is running on port 3000"));
This is my jwt file which uses a middleware function on posts request
import express from "express";
import jwt from "jsonwebtoken";
import authenticateToken from "./middlewares/authenticateToken.js";
const app = express();
app.use(express.json());
app.get("/", (req, res) => res.send("Node and JWT"));
app.post("/login", (req, res) => {
const user = {
id: 1,
username: "JhonDoe",
email: "Jhon#gmail.com",
};
const token = jwt.sign(user, "secret", { expiresIn: "1day" });
res.json({ token });
});
app.post("/posts", authenticateToken, (req, res) => {
const user = req.user;
res.json(user);
});
app.listen(4000, () => console.log("server is running on port 4000"));
And this is the middleware
export default function authenticateToken(req, res, next) {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1];
console.log(token);
if (!token) {
return res.status(401).json({ msg: "No token, authorization denied" });
}
try {
const user = jwt.verify(token, "secret");
req.user = user;
next();
} catch (err) {
console.log(token);
res.status(403).json({ msg: "Token is not valid" });
}
}
But when I import it, it doesn't work correctly if I show the token in the console it shows it correctly but it returns the error "token is not valid" but if I use it below the post request in the same jwt.js file it works perfectly it show me the payload, why doesn't it work when I import it?, thanks.
Solution
Instead of
export default function authenticateToken(req, res, next) {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1];
if (!token) {
return res.status(401).json({ msg: "No token, authorization denied" });
}
try {
const user = jwt.verify(token, "secret");
req.user = user;
next();
} catch (err) {
res.status(403).json({ msg: "Token is not valid" });
}
}
this
export default function authenticateToken(req, res, next) {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1];
if (!token) {
return res.status(401).json({ msg: "No token, authorization denied" });
}
jwt.verify(token, "secret", (err, user) => {
if (err) return res.status(403).json({ msg: "Token is not valid" });
req.user = user;
next();
});
}
Documentation https://github.com/auth0/node-jsonwebtoken#readme
Related
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)
}
})
Doesn't work the request (below) as needed, drops out into an error:
app.get('/protected', auth.isAuthenticated(User), function(req, res) {
res.send('Hoooora! Authentificated!');
});
The isAuthenticated function is called from the auth.js file:
auth.js:
const SECRET = 'secret-message';
const jwt = require('jsonwebtoken');
const { expressjwt: expressJwt } = require('express-jwt');
const compose = require('composable-middleware');
function sign(user) {
return jwt.sign({
_id: user._id,
}, SECRET, {
expiresIn: 60 * 60
});
}
function sendUnauthorized(req, res) {
console.log(req.headers.authorization);
console.log(req.user);
res.status(401).json ({ message: 'Unathorized' });
};
const validateJwt = expressJwt({
secret: SECRET,
algorithms: ['HS256'],
fail: sendUnauthorized,
getToken(req){
if(req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.access_token) {
return req.query.access_token;
}
return null;
}
});
function isAuthenticated(User) {
console.log('isAuthenticated is called');
return compose()
.use(validateJwt)
.use((req, res, next) => {
// Attach user to request
const { _id } = req.user;
console.log(_id + req.user);
User.findById(_id, function(err, user) {
if (err) return next(err);
if (!user) return sendUnauthorized(req, res);
req.user = user;
console.log('Successfuly verified user by token: ');
next();
});
});
};
module.exports = {
sign,
sendUnauthorized,
isAuthenticated,
};
I get an error when the isAuthenticated function runs. And I don't figure out how to fix it:
"error":{"message":"Cannot destructure property '_id' of 'req.user' as it is undefined."
There is a suspicion that the body-parser or express is not working. Although I did yarn add body-parser and yarn add express. In the index.js file code I also added the following:
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
I'm trying to add a simple middleware function for every request on the router level.
The docs are stating:
a middleware function with no mount path will be executed for every
request to the router
In my application I have only one router with one endpoint that is listening for every request and I'm placing my middleware function above this endpoint, but the middleware never gets launched.
Express setup:
const initializeExpress = (): void => {
const port = process.env.PORT;
const app = express();
app.use(helmet());
app.use(express.json());
app.use(cors());
app.use('/api', Router);
app.listen(port, () => {
console.log(`Listening for requests at http://localhost:${port}`);
});
};
My router code:
const Router = express.Router();
Router.use((req, res, next) => {
const token = req.header('authorization');
if (!token) res.status(401).send({ message: 'Unauthorized' });
const isAuthenticated = isAuthorized(token!);
if (isAuthenticated) {
next();
} else {
res.status(401).send({ message: 'Unauthorized' });
}
});
Router.get(
'/:arg1/:arg1Id?/:arg2?/:arg2Id?/:arg3?/:arg3Id?/:arg4?/:arg4Id?',
async (req, res): Promise<void> => {
const routeParams = filterRouteParams(req.params);
const path = basePath + getPathFromRouteParams(routeParams) + '/data.json';
if (await pathExists(path)) {
const data = await getJsonFromPath(path);
if (!isEmpty(data)) {
res.status(200).json(data);
return;
}
res.status(400).send({ message: 'Data not found' });
}
}
);
What am I doing wrong here?
On which route the middleware will be active, you need to define it.
There's two way to make this
First, call middleware before the your route:
const Router = express.Router();
const myMiddleware = (req, res, next) => {
const token = req.header('authorization');
if (!token) res.status(401).send({ message: 'Unauthorized' });
const isAuthenticated = isAuthorized(token!);
if (isAuthenticated) {
next();
} else {
res.status(401).send({ message: 'Unauthorized' });
}
}
Router.get(
'/:arg1/:arg1Id?/:arg2?/:arg2Id?/:arg3?/:arg3Id?/:arg4?/:arg4Id?',
myMiddleware(), //Call middleware here
async (req, res): Promise<void> => {
const routeParams = filterRouteParams(req.params);
const path = basePath + getPathFromRouteParams(routeParams) + '/data.json';
if (await pathExists(path)) {
const data = await getJsonFromPath(path);
if (!isEmpty(data)) {
res.status(200).json(data);
return;
}
res.status(400).send({ message: 'Data not found' });
}
}
);
Second, calling middleware for all routes that you define:
const Router = express.Router();
const myMiddleware = (req, res, next) => {
const token = req.header('authorization');
if (!token) res.status(401).send({ message: 'Unauthorized' });
const isAuthenticated = isAuthorized(token!);
if (isAuthenticated) {
next();
} else {
res.status(401).send({ message: 'Unauthorized' });
}
}
Router.use('/:arg1/:arg1Id?/:arg2?/:arg2Id?/:arg3?/:arg3Id?/:arg4?/:arg4Id?', myMiddleware());
Router.get(
'/:arg1/:arg1Id?/:arg2?/:arg2Id?/:arg3?/:arg3Id?/:arg4?/:arg4Id?'
async (req, res): Promise<void> => {
const routeParams = filterRouteParams(req.params);
const path = basePath + getPathFromRouteParams(routeParams) + '/data.json';
if (await pathExists(path)) {
const data = await getJsonFromPath(path);
if (!isEmpty(data)) {
res.status(200).json(data);
return;
}
res.status(400).send({ message: 'Data not found' });
}
}
);
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;
Background
I am tryng to do an simple authtentication system using jwt and mysql+sequelize here
What I had being able to do so far
I am being able to login and generate a token after that.
Problem
After being logged in, when I try to check the jwt token with a middleware on a particular route, it simply says that the token was not found.
What I tried to do
Since the token should be found at the req.headers['x-access-control'] or ['authorization'] I tried to console.log(req.headers) when I call the middleware but there is nothing about these two headers... Then I think that the problem might be there, but I have no idea on how to solving this :(
Pieces of code
This is the middleware (userController.js) which I use to login (signIn) and to verify the token (verifyToken)
var bcrypt = require("bcryptjs");
var jwt = require("jsonwebtoken");
const config = require("../config/config");
const User = require("../models").User;
module.exports = {
signIn(req, res) {
console.log("Sign-In");
User.findOne({
where: {
email: req.body.email
}
})
.then(user => {
if (!user) {
return res.status(404).send("User not found");
}
var passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res
.status(401)
.send({
auth: false,
accessToken: null,
reason: "Invalid Password"
});
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400 // expires in 24 hours
});
res.status(200).send({ auth: true, accessToken: token });
})
.catch(err => {
res.status(500).send("Error =>" + err);
});
},
verifyToken(req, res) {
console.log(req.headers);
let token =
req.body.token ||
req.query.token ||
req.headers["x-access-token"] ||
req.headers["authorization"];
if (!token) {
return res.status(403).send({
auth: false,
message: "No token provided"
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.status(500).send({
auth: false,
message: "Fail to Authentication. Error -> " + err
});
}
req.userId = decoded.id;
next();
});
}
};
and here is the app.js file with the Routes
const express = require("express");
const app = express();
const port = 3000;
const Sequelize = require("sequelize");
const sequelize = new Sequelize("mydb", "root", "Metin.234", {
host: "localhost",
dialect: "mysql"
});
sequelize
.authenticate()
.then(() => {
console.log("Connection with sequelize has been established successfully");
})
.catch(err => {
console.error("Unable to connect", err);
});
const userController = require("./controllers").user;
var bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.set("view engine", "ejs");
app.use(express.static(__dirname + "/public"));
app.get("/", (req, res) => {
res.render("home");
});
app.get("/register", (req, res) => {
res.render("register");
});
app.get("/login", (req, res) => {
res.render("login");
});
app.post("/login", userController.signIn);
app.get("/showAll", userController.verifyToken);
app.listen(port, () => {
console.log("server started!");
});
Thanks in advance, any help is appreciated! =D
EDIT
I saved the token on a variable called globalToken, so then it could be used on the verify token function (EDIT 2 and it works fine for what I want), however I am wondering on how can I get the value of accesstoken that is inside the response object that I am sending after the login proccess.