After a few hours of research for a good logical and semantic prototype, i found a good solution. router.put('/:articleId', AuthGuard([{ role: 'user', when: isOwner }, { role: 'admin' }]), async (req, res) => { }); A predicate function can be added to a specific role for more flexibility. In this example, the user can only update an item "when" it owns it. The little module : import passport from 'passport'; import { Request, Response, NextFunction } from 'express'; export const AuthenticateGuard = passport.authenticate('jwt', { session: false }); export interface IAuthorizeItem { role: string; when?: (req: Request) => boolean; }; export default function AuthGuard(items?: IAuthorizeItem[]) { return [AuthenticateGuard, AuthorizeGuard(items)]; }; export function AuthorizeGuard(items?: IAuthorizeItem[]) { return async function (req: Request, res: Response, next: NextFunction) { let user = req.user; if (!user) { return res.status(500).send('Access not allowed !'); } if (typeof req.user.hasRole !== 'function') { throw new Error('User object must have hasRole method'); } if (!items || items.length == 0) { return next(); } for (let item of items) { if (req.user.hasRole(item.role)) { if (!item.when) { return next(); } else { if (item.when(req)) { return next(); } } } } res.status(500).send('Access not allowed !'); } }; Note: I avoid any dynamic types checking because i used typescript and this module must be used only with static object.