I am trying to integrate passport in NestJS and to get current auth info anywhere using a decorator. My NestJs version was so old, I updated the NestJS version and changed to the code below. After I changed middleware code, I can no longer get current auth info.
How to get auth info using the changed middeware?
Code before changing the middleware:
export class authMiddlware implements NestMiddleware {
async resolve(): Promise<MiddlewareFunction> {
return async (req, res, next) => {
passport.authenticate('jwt', { session: false }, (err, user, info) => {
if (err) {
return next(err);
}
if (user) {
req.user = user;
}
return next();
})(req, res, next);
};
}
After changing the middleware:
In passport.authenticate I can get the changed user from the request, but out of passport, I cannot get the user from the request.
#Injectable()
export class authMiddlware implements NestMiddleware {
use(req: Request, res: Response, next: Function) {
passport.authenticate('jwt', { session: false }, (err, user, info) => {
if (err) {
return next(err);
}
if (user) {
req.user = user;
}
console.log(req.user)
next();
})(req, res, next);
console.log(req.user)
};
}
The user.decorator:
export const passUser= createParamDecorator((data, req) => {
return plainToClass(User, req.user);
});
Related
interface CustomRequest<T> extends Request {
user?: IUser,
body: T
}
interface CreateBody {
email:string;
}
interface deleteBody {
id:string;
}
router.post('/create', authenticate, (req:CustomRequest<CreateBody>, res) => {
Content.Create({
email:req.body.email
})
}
router.post('/delete', authenticate, (req:CustomRequest<deleteBody>, res) => {
Content.Create({
id:req.body.id
})
}
export const authenticate = async (
req: CustomRequest<null>
res: Response,
next: NextFunction,
) => {
try {
const user = await User.findToken(req.cookies.auth);
if (!user) return res.send({ success: false });
req.user = user;
next();
} catch (err) {
return res.send({ success: false });
}
};
I want to specify the request type by situation when designating middleware in nodejs.
req:CustomRequest
I've tried generics this way, but it doesn't work.
How can I define the type gracefully?
I would like to specify the type that some api have an e-mail in body and some api have a password in it.
How can we use graphql shield with passport js for JWT authentication
I have used the bellow code to implement that functionality but i think the parameters are not allowing the function to run
// graphql_shield.ts
const isAuthorized = rule({ cache: false })(
async (parent, args, ctx, info):Promise<any> => {
return await passportAuth.authenticateJwt;
},
);
// passport.ts
async authenticateJwt (req:any, res:Response, next:NextFunction) {
passport.authenticate('jwt', { session: false }, (error, user) => {
if (user) {
req.logged_in_user = user;
}
next();
})(req, res, next);
}
I want to use middleware to authenticate the JWT in the Bearer token
How can i inject my middleware function 'checkAuthenticated' into my get route below?
not sure how to properly inject the code below. Please let me know. thank you very much.
function checkAuthenticated(req, res, next) {
if(!req.header('authorization')) {
return res.status(401).send({message: 'Unauthorized request. Missing authentication header'});
}
let token = req.header('authorization').split(' ')[1];
let payload = jwt.decode(token, '123');
if(!payload) {
return res.status(401).send({message: 'Unauthorized request. Authetication header invalid'});
}
req.user = payload;
next();
}
router.route('/:user_id')
.get((req, res) => {
User.findById(req.params.user_id, (err, user) => {
if (err) {
res.send(err);
} else {
res.json(user);
}
});
})
There are a few options here. I typically use:
router.use('*', checkAuthenticated);
Another option is:
router.get('/:user_id', checkAuthenticated, (req, res) => { ... })
Or, using your example of router.route...:
router.route('/:user_id').get(checkAuthenticated, (req, res) => { ... })
You can also chain them together:
router.route('/:user_id').get(checkAuthenticated).get((req, res) => { ... })
check this hope it will help you
router.route('/:user_id')
.all((req, res, next) => {
if (req.user) {
next();
} else {
res.redirect('/');
}
})
.get((req, res) => {
res.json(req.user);
});
I am following a middleware chaining example from this question.
I have a route app.put('/users/:id', isAuthenticated, (req, res) => {db.updateUser(req.params.id, req.body)}. I am trying to write a middleware function that verifies that the ID provided in the URL matches the ID retrieved from the JWT included with the request.
I already have a function isAuthenticated that verifies the JWT and sets res.locals.userId to the UID retrieved; so I would like to simply make use of that in this new function canModifyTarget but for some reason the request hangs forever:
// This function works fine
isAuthenticated: function(req, res, next) {
let token;
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
token = req.headers.authorization.split(' ')[1];
admin.auth().verifyIdToken(token).then((decodedToken) => {
res.locals.userId = decodedToken.uid;
return next();
}).catch((error) => {
return res.status(HttpStatus.UNAUTHORIZED).send();
})
}
}
// Switching out isAuthenticated for this in the route causes a permanent hang
canModifyTarget: function(req, res, next) {
console.log('This is printed');
return (req, res, next) => {
console.log('This is NOT printed');
isAuthenticated(req, res, () => {
if (req.params.id === res.locals.userId) {
return next();
}
return res.status(HttpStatus.FORBIDDEN).send();
})
}
}
middlewares should be callback functions that call "next()" once finished.
Your first function, when executed, is calling next() (eventually, after your promise is resolved)
Your second function isn't calling next(), it is just returning a function definition.
Define it like this
canModifyTarget: function(req, res, next) {
isAuthenticated(req, res, () => {
if (req.params.id === res.locals.userId) {
return next();
}
return res.status(HttpStatus.FORBIDDEN).send();
})
}
}
and if the third parameter of isAuthenticated is a callback, it should work
Also, you should define an "else" case in your isAuthenticated function, otherwise it will hang as well (maybe throw an exception or something?)
If you need to reference them, store them in variables rather than directly defining them in your module.exports:
const isAuthenticated = function(req, res, next) {
// code here
}
const canModifyTarget: function(req, res, next) {
// code here
}
module.exports = {
isAuthenticated,
canModifyTarget,
};
I think simpler is to define canModifyTarget as one more middleware. I.e:
function canModifyTarget(req, res, next) {
console.log('This is NOT printed');
if (req.params.id === res.locals.userId) {
return next();
}
return res.status(HttpStatus.FORBIDDEN).send();
}
and then just apply it after isAuthenticated middleware:
app.put(
'/users/:id',
isAuthenticated,
canModifyTarget,
(req, res) => {db.updateUser(req.params.id, req.body)}
);
Hope it helps.
I am just writing a solution where I needed to unify two kind of auth middlewares: password-based and apikey-based into one middleware: unifiedOrgAuth middleware.
So, basically this would enable me to just put unifiedOrgAuth middleware on those routes which need either the password-based or apikey-based auth.
The key thing was to pass the next function from the umbrella middleware to the underlying middleware by just calling the underlying middleware with the next function of the umbrella middleware:
unified auth middleware:
function unifiedOrgAuthMiddleware(
path: string,
perm: Permission
): express.RequestHandler {
return async (req: RequestWithOrg, _res: Response, next: NextFunction) => {
const cookies = req.cookies;
if (cookies && cookies.Authorization) {
(userAuthMiddleware(path, perm))(req, _res, next);
return;
}
const apiKey = req.header('X-API-KEY');
if (apiKey && apiKey.length > 0) {
(apiAuthMiddleware(path, perm))(req, _res, next);
return;
}
return next(new Error401Exception());
// Make linter happy.
};
}
Here are the underlying middlewares:
password-based auth middleware:
function userAuthMiddleware(
path: string,
perm: Permission
): express.RequestHandler {
return async (req, _res, next) => {
try {
const cookies = req.cookies;
if (!(cookies && cookies.Authorization)) {
next(new Error401Exception());
// Make linter happy.
return;
}
if (!validCookies(cookies)) {
next(new Error401Exception());
// Make linter happy.
return;
}
} catch (error) {
next(new Error401Exception());
// Make linter happy.
return;
}
next();
};
}
api-based auth middleware:
function apiAuthMiddleware(
path: string,
perm: Permission
): express.RequestHandler {
return async (req: RequestWithOrg, _res: Response, next: NextFunction) => {
const apiKey = req.header('X-API-KEY');
if (!apiKey) {
next(new Error401Exception());
// Make linter happy.
return;
}
if (!validApiKey(apiKey)) {
next(new Error401Exception());
// Make linter happy.
return;
}
next();
};
}
I am new to Node.JS coming from a Java Background I am using express to build this Rest API . What I am trying to do is build the concept of a manager. I am looking for a elegant way of returning a user object in the following:
users route: user.js
router.get('/find/:email', function(req, res, next){
userWare.findUserByEmail(req, res, next)
});
middleware/manager: usermiddleware.js
module.exports = {
findUserByEmail: function(req, res, next) {
models.core_user.find({
where:{
email: req.params.email
}
}).then(function(user){
res.json(user)
}, function(err){
res.status(404).json(err);
});
},
}
So In this above function I would like to return the user object to the route instead of the json. so that I can create the json from the object in the route. The whole point of this manager class will be to fectch and return objects.
What you need to do is call the callback function with the data you need or return the promise.
Callback
user.js
router.get('/find/:email', function (req, res, next) {
userWare.findUserByEmail(req.params.email, function (err, data) {
// error as first parameter or null if no error occurred
if (err) {
return res.status(404).json(err);
}
res.json(user);
});
});
usermiddleware.js
module.exports = {
findUserByEmail: function (email, next) {
models.core_user.find({
where: {
email: email
}
}).then(
function (user) {
// async call of callback with user object
next(null, user);
},
function (err) {
// async call of callback with error
next(err);
}
);
}
};
Promise
You could also just return the promise returned by your model, then it would look like this:
user.js
router.get('/find/:email', function (req, res, next) {
userWare.findUserByEmail(req.params.email).then(
function (user) {
res.json(user);
},
function (err) {
res.status(404).json(err)
}
);
});
usermiddleware.js
module.exports = {
findUserByEmail: function (email) {
// return the promise to the caller
return models.core_user.find({
where: {
email: email
}
});
}
};