I'm using express-jwt in my project but I'm getting this error, I couldn't find the solution
import jwt from "express-jwt";
const getTokenFromHeaders = (req) => {
const { headers: { authorization } } = req
if (authorization && authorization.spilt(' ')[0] === 'Token') {
return authorization.split(' ')[1]
}
return null
}
const auth = {
required: jwt({
secret: " /\-l/\Y",
userProperty: 'payload',
getToken: getTokenFromHeaders
}),
optional: jwt({
secret: "/\-l/\Y",
userProperty: 'payload',
getToken: getTokenFromHeaders,
credentialsRequired: false,
})
}
export default auth
this use
router.post("/login", auth.optinal, (req, res, next) => {
const { body: { user } } = req
if (!user.email && !user.password) {
return res.status(402).json({
errors: "Eposta veya şifre yanlış ! ",
});
return passport.authenticate('local', { session: false }, (err, passportUser, info)
=> {
if (err) {
return next(err)
}
if (passportUser) {
const user = passportUser
user.token = passportUser.genareteJWT();
return res.json({ user: user.toAuthJSON() })
}
return res.status(400).info;
})(req, res, next)
}
})
and error message:
required: jwt({
^
TypeError: jwt is not a function
at file:///C:/Users/atala/Desktop/atalayapp-main/backend/middleware/auth/auth.js:12:15
at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
at async loadESM (node:internal/process/esm_loader:88:5)
at async handleMainPromise (node:internal/modules/run_main:61:12)
Related
I'm using the custom error handling of passportjs. When I finished authenticating and now redirect to other route, the req.user is now undefined on that route. Are there any configurations I need to do?
(req: any, res, next) => {
passport.authenticate('local-register', (err, user, info) => {
if (err) {
return next('Error Auth');
}
if (info) {
return next('Error Auth');
}
if (!user) {
return next('Error Auth');
}
req.logIn(user, (error: Error) => {
if (error) {
return next('Error Auth');
}
return next();
});
})(req, res, next);
app.get('/home', async (req, res, next) => {
console.log(req.user.id) // logs undefined
})
session.js file includes
const sessions = session({
cookie: {
maxAge: 86400000,
httpOnly: true,
secure: process.env.NODE_ENV === 'production' ? true : 'auto',
sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax',
},
name: 'sessionID',
genid: () => {
return nanoid(36);
},
resave: false,
secret: process.env.SESSION_SECRET ?? '',
saveUninitialized: false,
store: new Reddistore({ client: redisClient }),
});
my index.js file includes
app.use(sessions);
app.use(passport.initialize());
app.use(passport.session());
in your index.js file
const passport = require('passport');
const { passportStrategy } = require('./config/passportStrategy');
passportStrategy(passport);
in config/passportStrategy.js file
const {
Strategy, ExtractJwt
} = require('passport-jwt');
const User = require('../model/user');
const passportStrategy = (passport) => {
const options = {};
options.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
options.secretOrKey = "YOUR_SECRET";
passport.use('local-register',
new Strategy(options, async (payload, done) => {
try {
const result = await User.findOne({ _id: payload.id });
if (result) {
return done(null, result.toJSON());
}
return done('No User Found', {});
} catch (error) {
return done(error,{});
}
})
);
};
module.exports = { passportStrategy };
// your middleware should like this
(req: any, res, next) => {
passport.authenticate('local-register', (err, user, info) => {
if (err) {
return next('Error Auth');
}
if (info) {
return next('Error Auth');
}
if (!user) {
return next('Error Auth');
}
req.user = user; // <=== assign user to req.user
req.logIn(user, (error: Error) => {
if (error) {
return next('Error Auth');
}
return next();
});
})(req, res, next);
app.get('/home', async (req, res, next) => {
console.log(req.user.id) // now you can access user
})
I am sending an auth request from chrome to my backend, there is payload chrome developer tool, it seems to have received the object, but I am backend
or: Cannot read properties of undefined (reading 'email')
It gives an error, I printed req.body from the console, it is empty object, what can I do?
backend
postmande works fine and logs in successfully
const { body: { user } } = req
console.log(req.body)
const userLogin = new User();
if (!user.email && !user.password) {
return res.status(402).json({
errors: "Eposta veya şifre zorunlu 😊 ! ",
});
}
return passport.authenticate('local', {
session: false,
successRedirect: '/home',
failureRedirect: '/login'
}, (err, passportUser, info) => {
if (err) {
return next(err)
}
if (passportUser) {
console.log(passportUser)
const user = passportUser
user.token = userLogin.generateJWT(user.email, user.id);
return res.json({ user: passportUser })
}
return res.status(400).json({ message: info });
})(req, res, next)
react fetch (client)
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
// const token = localStorage.getItem("X-CSRF-TOKEN");
const loginProccsess = async (e) => {
e.preventDefault()
const data = {
"user": {
email,
password
}
}
fetch("/api/auth/login", {
method: "POST",
mode: "cors",
// credentials: "some-origin",
header: {
"Content-type ": "application/json"
},
redirect: "follow",
body: JSON.stringify(data)
}).then((res) => {
console.log(res)
})
.catch(err => console.log(err))
}
I'm doing clienten post operation on my node js server, it works fine from postman, but clienten undefend returns
as i said from postman
{ "user": {
"email": "levlaaaaa#levla.com",
"password": "123" } }
When I throw the object, it works fine, but it returns undefined on the cilient side.
client request file (react)
const loginProccsess = async (e) => {
e.preventDefault()
const data = {
"user": {
"email":email,
"password": password
}
}
// return console.log(JSON.stringify(data))
await fetch("/api/auth/login", {
method: "POST",
mode: "cors",
// credentials: "some-origin",
header: {
"Content-type ": "application/json"
},
redirect: "follow",
body: JSON.stringify(data)
}).then((res) => {
console.log(res)
})
backend login.js (login router request)
router.post("/login", authOP, (req, res, next) => {
const { body: { user } } = req
const userLogin = new User();
console.log(user)
if (!user.email && !user.password) {
return res.status(402).json({
errors: "Eposta veya şifre zorunlu 😊 ! ",
});
}
return passport.authenticate('local', {
session: false,
successRedirect: '/home',
failureRedirect: '/login'
}, (err, passportUser, info) => {
if (err) {
return next(err)
}
if (passportUser) {
console.log(passportUser)
const user = passportUser
user.token = userLogin.generateJWT(user.email, user.id);
return res.json({ user: passportUser })
}
return res.status(400).json({ message: info });
})(req, res, next)
})
// app.js(server) (main file)
app.use(Sentry.Handlers.requestHandler());
app.use(cookieParser());
app.use(express.json())
app.use(cors());
app.use(session({
resave: false,
saveUninitialized: true,
secret: 'secret'
}))
app.use(passport.initialize())
app.use(passport.session())
I'm trying to chain 2 auth tokens in one endpoint, the user and the admin, to get all merchants.
I have tried several solutions posted by several people here on stackoverflow, with no luck. I'll post my code along with the solutions I tried below.
How can I make express to continue the process if the request has ONE of the 2 tokens, admin OR user?
Thanks in advance...
Admin auth:
const adminAuth = async (req, res, next) => {
try {
const token = req.header('Authorization');
if(!token) {
return res.status(401).json({ message: 'Unauthorized', success: false });
}
const newToken = req.header('Authorization').split(' ')[1];
const decoded = JWT.verify(newToken, key);
if(decoded.role != 'admin') {
return res.status(401).json(
{ message: 'Unauthorized, only an admin is authorized!', success: false }
);
}
const findAdmin = await Admin.findOne({ username: decoded.username });
if(!findAdmin){
return res.status(409).send({ message: `Admin doesn't exist!`, success: false });
}
} catch (err) {
console.log(err);
}
next();
}
User auth:
const userAuth = async (req, res, next) => {
try {
const token = req.header('Authorization');
if(!token) {
return res.status(401).json({ message: 'Unauthorized', success: false });
}
const newToken = req.header('Authorization').split(' ')[1];
const decoded = JWT.verify(newToken, key);
if(decoded.role != 'user') {
return res.status(401).json({ message: 'Unauthorized, only a user is authorized!', success: false });
}
const findUser = await User.findOne({ email: decoded.email });
if(!findUser){
return res.status(409).send({ message: `User doesn't exist!`, success: false });
}
} catch (err) {
console.log(err);
}
next();
}
The endpoint in question:
router.get('/getall', adminAuth, usertAuth, upload.none(), async (req, res) => {
const merchantsList = await Merchant.find();
if(!merchantsList) {
return res.status(500).send({ success: false });
}
return res.status(200).send({ merchants: merchantsList, success: true });
});
I tried the below solutions:
router.get('/getall', [adminAuth, usertAuth], upload.none(), async (req, res) => {
const merchantsList = await Merchant.find();
if(!merchantsList) {
return res.status(500).send({ success: false });
}
return res.status(200).send({ merchants: merchantsList, success: true });
});
router.get('/getall', [adminAuth || usertAuth], upload.none(), async (req, res) => {
const merchantsList = await Merchant.find();
if(!merchantsList) {
return res.status(500).send({ success: false });
}
return res.status(200).send({ merchants: merchantsList, success: true });
});
router.get('/getall', [adminAuth, usertAuth, upload.none(), async (req, res) => {
const merchantsList = await Merchant.find();
if(!merchantsList) {
return res.status(500).send({ success: false });
}
return res.status(200).send({ merchants: merchantsList, success: true });
}]);
router.get('/getall', [adminAuth, usertAuth, upload.none()], async (req, res) => {
const merchantsList = await Merchant.find();
if(!merchantsList) {
return res.status(500).send({ success: false });
}
return res.status(200).send({ merchants: merchantsList, success: true });
});
That's not how middlewares work in express for example let's look at getAll route
router.get('/getall', [adminAuth, usertAuth], upload.none(), async (req, res) => {
try{
//some code
}catch(e){
//handle error
}
});
if the user is not admin it will fail at adminAuth and end the request, so you have to think of middlewares as a chain or a pipleline they pass (req,res,next) to each other
so what you need here is not make a third middleware which is the combination of adminAuth and userAuth
async function adminAndUserAuth (req, res, next){
try {
const token = req.header('Authorization');
if(!token) {
return res.status(401).json({ message: 'Unauthorized', success: false });
}
const newToken = req.header('Authorization').split(' ')[1];
const decoded = JWT.verify(newToken, key);
if(decoded.role != 'admin' && decoded.role != 'user' ) {
return res.status(401).json(
{ message: 'Unauthorized, only an admin or user are authorized!', success: false }
);
}
const found = await Admin.findOne({ username: decoded.username }) ?? await User.findOne({ email: decoded.email });
if(!found){
return res.status(409).send({ message: `Admin doesn't exist!`, success: false });
}
} catch (err) {
console.log(err);
}
next();
}
and the new route will be
router.get('/getall' , adminAndUserAuth , async (req,res) => {});
I am building a frontend application that uses 2FA in addition to JWT to authorize a authenticated account. The middleware is set up as such:
const router = require('express').Router()
const jwt = require('jsonwebtoken')
const exjwt = require('express-jwt')
const jwtMW = exjwt({
secret: 'testing out a secret',
})
const getBearerToken = (header, callback) => {
if (header) {
console.log(header)
const token = header.split(' ')
if (token) {
return callback(null, token[0])
} else {
return callback('Malformed bearer token', null)
}
} else {
return callback('Missing authorization header', null)
}
}
const validateToken = (req, res, next) => {
getBearerToken(req.headers['authorization'], (error, token) => {
if (error) {
return res.status(401).json({ success: false, message: error })
}
jwt.verify(token, jwtMW, (error, decodedToken) => {
if (error) {
return res.status(401).send({
success: false,
error: 'Invalid authorization token',
})
}
if (decodedToken.authorized) {
req.decodedToken = decodedToken
next()
} else {
return res
.status(401)
.send({ success: false, error: '2fa is required' })
}
})
})
}
I run it on protected routes like this:
router.get('/:id/profile', validateToken, (req, res) => {
User.findById(req.params.id)
.then(user => res.json(user))
.catch(err => res.status(400).json('Error: ' + err))
})
EDIT, ADDITIONAL ROUTE
And another route that fetches the token here:
router.post('/verifycheck', (req, res) => {
let tel = `+1${req.body.tel}`
const code = req.body.code
getBearerToken(req.headers['authorization'], (error, token) => {
if (error) {
console.log(error)
return res.status(401).json({ success: false, message: error })
}
if (!code) {
return res.status(401).json({
success: false,
message: 'A verification code is required',
})
}
jwt.verify(token, jwtMW, (error, decodedToken) => {
// client refers to Twilio Verify service //
client.verify
.services('xxxxxxxxxxxxxxxxxxxxx')
.verificationChecks.create({ to: tel, code: code })
.then(verification_check => {
console.log(error)
console.log(decodedToken)
if (verification_check.valid) {
decodedToken.authorized = true
console.log(decodedToken)
var token = jwt.sign(decodedToken, jwtMW, {
expiresIn: 129600,
})
return res.json({ verification_check, token })
} else {
return res.status(401).json({
success: false,
message: 'Invalid verification code',
})
}
})
.catch(err => {
res.json(err.message)
console.log(err)
})
})
})
})
And it throws an error that crashes the server, saying
TypeError: next is not a function
at middleware (D:\Users\Capstone Design\Desktop\learningmongodb\mern-rod\node_modules\express-jwt\lib\index.js:76:16)
at Object.module.exports [as verify] (D:\Users\Capstone Design\Desktop\learningmongodb\mern-rod\node_modules\jsonwebtoken\verify.js:94:10)
at getBearerToken (D:\Users\Capstone Design\Desktop\learningmongodb\mern-rod\backend\routes\index.js:109:13)
at getBearerToken (D:\Users\Capstone Design\Desktop\learningmongodb\mern-rod\backend\routes\index.js:22:20)
at router.post (D:\Users\Capstone Design\Desktop\learningmongodb\mern-rod\backend\routes\index.js:97:5)
I see where the error is happening, but I'm unsure of how to fix this error.
EDIT
I realized that jwt.verify doesn't accept callbacks as an argument. When I removed the callback function and ran the verify function in a try/catch statement, things worked as expected.
const validateToken = (req, res, next) => {
getBearerToken(req.headers['authorization'], (error, token) => {
if (error) {
return res.status(401).json({ success: false, message: error })
}
let decoded = ''
try {
decoded = jwt.verify(token, 'testing out a secret')
} catch (error) {
return res.status(401).send({
success: false,
error: 'Invalid authorization token',
})
}
if (decoded.authorized) {
req.decodedToken = decoded
next()
} else {
return res
.status(401)
.send({ success: false, error: '2fa is required' })
}
})
}