How to bind or pass req parameter to Passport.js JWT Strategy? - node.js

I want to store information in the database when user is authenticated. The information is coming form the client in the request. The following code throws error, saying req is not defined.
Controller:
exports.verifySession = async function(req, res, next) {
let responses = [];
passport.authenticate('jwt', async (error, result) => {
if (error) {
email.sendError(res, error);
} else if (result === false) {
responses.push(new CustomResponse(1).get());
return res.status(422).json({ data: { errors: responses } });
}
if (result.SessionToken) {
return res.status(200).json('valid');
} else {
return res.status(401).json();
}
})(req, res, next);
};
And passport.js:
passport.use(
new JWTstrategy(
{
// We expect the user to send the token as a query paramater with the name 'token'
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
// Secret we used to sign our JWT
secretOrKey: config.jwtkey
},
async (token, done) => {
console.log(req.body);
try {
const user = new User();
user.UserID = token.user.UserID;
user.SessionToken = token.user.SessionToken;
user.SessionDate = token.user.SessionDate;
user.ProviderID = token.user.ProviderID;
// Verify session token
await user.verifySessionToken(user, async (error, result) => {
if (error) {
return done(error);
} else if (result.returnValue === 0) {
return done(null, token.user);
} else if (result.returnValue !== 0) {
return done(null, result);
}
});
} catch (error) {
done(error);
}
}
)
);

You can use passReqToCallback feature of passport to pass your request body to passport.
From passport.js official docs :
The JWT authentication strategy is constructed as follows:
new JwtStrategy(options, verify)
options is an object literal
containing options to control how the token is extracted from the
request or verified.
...
...
passReqToCallback: If true the request will be passed to the verify
callback. i.e. verify(request, jwt_payload, done_callback).
You can try this:
passport.use(new JWTstrategy({
// We expect the user to send the token as a query paramater with the name 'token'
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
// Secret we used to sign our JWT
secretOrKey: config.jwtkey,
//this will help you to pass request body to passport
passReqToCallback: true
}, async (req, token,done) => {
//req becomes the first parameter
// now you can access req.body here
})
Note: req becomes the first parameter of callback function instead of token, when you use passReqToCallback

Related

error 500 internal server error express-jwt

I'm having trouble figuring out why postman keeps returning empty curly braces with 500 internal server error whenever in use Bearers token in authorization for POST 'http://localhost:3000/api/v1/products' isAdmin true. This is my jwt.js file
const { expressjwt: expressJwt } = require('express-jwt');
function authJwt() {
const secret = process.env.secret
const api = process.env.API_URL
return expressJwt({
secret,
algorithms: ['HS256'],
isRevoked: isRevoked
}).unless({
path: [
{ url: /\/api\/v1\/products(.*)/, methods: ['GET', 'OPTIONS'] },
{ url: /\/api\/v1\/categories(.*)/, methods: ['GET', 'OPTIONS'] },
`${api}/users/login`,
`${api}/users/register`,
]
})
}
async function isRevoked(req, payload, done) {
if(!payload.isAdmin) {
done(null, true);
}
done();
};
module.exports = authJwt
Upon introducing this lines of codes, Postman returns authorization error even with the Bearers token. My good developers, come through for me here. I've been stuck for a whole week.
My aim is the API should post the new product using isAdmin [true] bearer's token.
async function isRevoked(req, token) {
if(!token.payload.isAdmin) {
return true
}
return undefined;
}
The error-handler file
function errorHandler(err, req, res, next) {
if (err.name === 'UnauthorizedError') {
return res.status(401).json({message: 'The user is not authorized'})
}
if (err.name === 'ValidationError') {
return res.status(401).json({message: err})
}
return res.status(500).json(err);
}
module.exports = errorHandler
In your app.js use authJwt() instead of just authJwt
use following
async function isRevoked(req, token){
if(!token.payload.isAdmin) {
return true;
}
}
and comment out
async function isRevoked(req, payload, done) {
if(!payload.isAdmin) {
done(null, true);
}
done();
};
and comment out
async function isRevoked(req, token) {
if(!token.payload.isAdmin) {
return true
}
return undefined;
}
in your jwt.js
Increase your token time from 1d to more days say 10d
Get your fresh Token

How to pass jwtPayload data decoded by Passport to nodejs API

I am using this passport strategy.
passport.use(
'onlyForRefreshToken',
new JWTStrategy(
{
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
secretOrKey: jwtSecretRider,
},
(jwtPayload, done) => {
if (jwtPayload) {
return done(null, jwtPayload);
}
return done(null, false);
},
),
);
My goal is Putting 'jwtPayload' into my rest API of Nodejs that is located at other folder.
That is, I want to use jwtPayload decoded at the code below.
exports.riderRefreshToken = async (req, res) => {
const { email } = req.body;
const exRiderRefreshToken = await Rider.findOne({ email });
}
And this router works by middleware of jwtstrategy.
router.post(
'/refreshToken',
passport.authenticate('onlyForRefreshToken', { session: false }),
authenticationCtrl.riderRefreshToken,
);
In conclusion, when JWT passes from jwtstrategy without problem, that Post router would work.
And I want to use jwtPayload that is in jwtstrategy into Nodejs API as req.params or req.body.
Could you help me this problem?
You need to wrap your strategy into a function that gets req and res :
const isAuthenticated: RequestHandler = (req, res, next) => {
passport.authenticate(
'jwt',
{ session: false, failWithError: true },
(error, user) => {
if (error) {
return next(error)
}
//HERE PUT USER WHERE YOU WANT
//req.data or req.user or req.userInfo
req.user = user
return next()
}
)(req, res, next)
}
I don't recommend putting the user into req.params nor req.body since it might be confusing later on (because technically it doesn't come from those).

Integrating json web token in oauth20

I am trying to create an api where user can sign up with an email or can sign in with google, I use json web token for authentication and oauth20, the problem is, can, I pass a jwt with oauth?
I have tried passing it and, I get a token if, I console log, but how do, I pass it to the user, like can i some way attach it to the req.user object in the cb by oauth or something like that?
I am doing this in the google strategy:
async (accessToken, refreshToken, params, profile, cb) => {
const userCheck = await User.findOne({ googleId: profile.id });
if (userCheck) {
const payload = {
user: {
id: userCheck.id
}
};
jwtToken.sign(
payload,
config.get("jwtSecret"),
{ expiresIn: 360000 },
(err, token) => {
if (err) {
throw err;
}
// console.log(token);
return res.json({ token });
},
cb(null, userCheck)
);
My routes are protected like this:
router.get("/", auth, async (req, res)=>{
...some code
}
where auth is a middle ware function
This is the Auth middleware function:
module.exports = function(req, res, next) {
const token = req.header("x-auth-token");
// If no token found
if (!token)
{
return res.status(401).json({ msg: "User not authorized" });
}
// Set token to user
try {
const decoded = jwtToken.verify(token, config.get("jwtSecret"));
req.user = decoded.user;
}
catch (err)
{
res.
status(401)
.json({ msg: "User not authenticated, please login or sign up" });
}
next();
};
I found the solution, you need to pass sign the token in the passport.serializeUser and then send the it with a redirection in response of the redirect url.
The serialize user function:
passport.serializeUser(async (user, cb) => {
const payload = {
user: {
id: user.id
}
};
token = jwtToken.sign(payload, config.get("jwtSecret"), {
expiresIn: 360000
});
console.log("serialize");
cb(null, user.id);
});
The redirection route:
router.get(
"/google/redirect",
passport.authenticate("google", { sessionStorage: false }),
(req, res) => {
res.redirect("/" + token);
}
);

How to resolve Passport-jwt token unauthorized error?

I am persistently getting 'unauthorized' error while authenticating using a JWT. Below is my controller code:
exports.loginPost = async (req, res) => {
winston.info('Calling loginPost()...');
passport.authenticate('local', { session: false }, (err, user, info) => {
if (err) {
return utils.errorHandler(res, err);
} else if (!user) {
return utils.errorHandler(res, {
statusCode: 403,
message: 'Incorrect username or password.'
});
}
const token = jwt.sign(user, sharedSecret, { expiresIn: '24h' });
//req.user = user;
return res.json({ user, token });
// req.login(user, { session: false }, (err) => {
// if (err) {
// res.send(err);
// }
// // generate a signed json web token with the contents of user object and return it in the response
// const token = jwt.sign(user, sharedSecret, { expiresIn: '24h' });
// //req.user = user;
// return res.json({ user, token });
// });
})(req, res);
};
exports.isUserLoggedIn = async (req, res) => {
let login = {"message": "all good !"}
console.log(req)
return res.status(200).json(login);
//return res.status(200).json(req.user);
};
and passport.js strategy script is as follows:
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
}, async function (username, password, cb) {
//this one is typically a DB call. Assume that the returned user object is pre-formatted and ready for storing in JWT
try {
let user = await userService.getUserWithPassword(username, password);
console.log("passport.js: ",user);
if (!user || user.walletKey !== password) {
throw { statusCode: 403, message: 'Incorrect username or password.' };
}
// // purge password field
// delete user.currentPassword;
return cb(null, user, { message: 'Logged In Successfully' });
} catch (err) {
cb(err);
}
}));
passport.use(new JWTStrategy({
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
secretOrKey: sharedSecret,
passReqToCallback: true
},
async function (req, jwtPayload, cb) {
// Return user object from the JWTPayload
try {
let user = await userService.getUserWithPassword(jwtPayload.walletName, jwtPayload.walletKey);
console.log("passport.js: ",user);
req.user = user
return cb(null, user); //jwtPayload
} catch(err){
return cb(err,false);
}
}
));
I am able to generate token successfully, however, on calling isUserLoggedIn method using Bearer Token, it's prompting me unauthorized error. I am not making an traditional db call to login, instead I am just creating account in a Hyperledger-Indy pool nodes. Using swagger express middleware on a Node.js app.
Adding isUserLoggedIn method script below:
exports.isUserLoggedIn = async (req, res) => {
//let login = {"message": "all good !"}
console.log(req)
return res.status(200).json(req.user);
//return res.status(200).json(req.user);
};

Passport JWT Strategy extracting options

Using Passport JWT Strategy, I'm passing the token down via params, and extracting the token like this ExtractJWT.fromUrlQueryParameter('secret_token').
But sometimes I'm passing the token down via header, I would like to extract it like this ExtractJWT.fromHeader('secret_token').
How can I check how its being passed down and use the correct extracting method dynamically.
This is my code:
passport.use(new JWTstrategy({
secretOrKey: process.env.AUTH_SECRET,
jwtFromRequest: ExtractJWT.fromUrlQueryParameter('secret_token')
}, async (token, done) => {
try {
//Pass the user details to the next middleware
return done(null, token.user);
} catch (error) {
done(error);
}
}));
Thank you! Im on this for a long time....
Use ExtractJwt.fromExtractors() method
var jwtStrategy = new JwtStrategy({
// this will try to extract from Query parm, header and Authheader
jwtFromRequest: ExtractJwt.fromExtractors([ExtractJwt.fromUrlQueryParameter("secret_token"), ExtractJwt.fromHeader("secret_token"), ExtractJwt.fromAuthHeaderAsBearerToken()]),
//here we have defined all possible extractors in an array
secretOrKey: process.env.AUTH_SECRET
}, async (payload, done) => {
...
});
The method has been added to extract token from header. Pass it as:
Authorization: Bearer {token}
Content-Type : application/json
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
try this way :
const options = {};
options.jwtFromRequest = ExtractJWT.fromUrlQueryParameter('secret_token')!=undefined?ExtractJWT.fromUrlQueryParameter('secret_token'):ExtractJWT.fromHeader('secret_token');
options.secretOrKey = process.env.AUTH_SECRET;
passport.use(new JWTstrategy(options, async (token, done) => {
try {
//Pass the user details to the next middleware
return done(null, token.user);
} catch (error) {
done(error);
}
}));
Answer:
Here is a workaround...
It looks for query params or headers with the name secret_token .
var url = require('url');
const options = {};
options.jwtFromRequest = (request) => {
var token = null;
var param_name = 'secret_token' //parameter name
var parsed_url = url.parse(request.url, true);
if (request.headers[param_name]) {
token = request.headers[param_name];
}
else if (parsed_url.query && Object.prototype.hasOwnProperty.call(parsed_url.query, param_name)) {
token = parsed_url.query[param_name];
}
return token;
}
options.secretOrKey = process.env.AUTH_SECRET;
passport.use(new JWTstrategy(options, async (token, done) => {
try {
//Pass the user details to the next middleware
return done(null, token.user);
} catch (error) {
done(error);
}
}));

Resources