添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I am trying to make use of the AuthGuard decorator, and the passport JWT strategy, following the documentation .

Everything in the documentation works great. But I now want to protect a route with a scope contained in the JWT. So here is a basic jwt payload generated by my application:

"user": { "id": "20189c4f-1183-4216-8b48-333ddb825de8", "username": "user.test@gmail.com" "scope": [ "manage_server" "iat": 1534766258, "exp": 1534771258, "iss": "15f2463d-8810-44f9-a908-801872ded159", "sub": "20189c4f-1183-4216-8b48-333ddb825de8", "jti": "078047bc-fc1f-4c35-8abe-72834f7bcc44"

Here is the basic protected route being guarded by the AuthGuard decorator:

@Get('protected')
@UseGuards(AuthGuard('jwt'))
async protected(): Promise<string> {
    return 'Hello Protected World';

I would like to add options and restrict the access of that route to the people having the manager_server scope into their JWT. So after reading a little bit of the AuthGuard code, I thought that I was able to write something like:

@Get('protected')
@UseGuards(AuthGuard('jwt', {
    scope: 'manage_server'
async protected(): Promise<string> {
    return 'Hello Protected World';

However, I can't see in the documentation where I could make use of this option.

I thought that adding an option argument to the validate function of the JWTStrategy could make the trick, but it does not. Here is my validate function (contained in the jwt.strategy.ts file):

async validate(payload: JwtPayload, done: ((err: any, value: any) => void)) {
    const user = await this.authService.validateUser(payload);
    if (!user) {
        return done(new UnauthorizedException(), false);
    done(null, user);

Thank you very much for your help and don't hesitate to ask me for more informations in the comments if you need so.

When you look at the code of the AuthGuard, it seems like the options.callback function is the only possible customization.

I think instead of writing your own AuthGuard that supports scope checks, it is cleaner to have a ScopesGuard (or RolesGuard) with its own decorater like @Scopes('manage_server') instead. For this, you can just follow the RolesGuard example in the docs, which also just checks an attribute of the JWT payload under the user property in the request.

Essential steps

Create a @Scopes() decorator:

export const Scopes = (...scopes: string[]) => SetMetadata('scopes', scopes);

Create a ScopesGuard:

@Injectable()
export class ScopesGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {}
  canActivate(context: ExecutionContext): boolean {
    const scopes = this.reflector.get<string[]>('scopes', context.getHandler());
    if (!scopes) {
      return true;
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    const hasScope = () => user.scopes.some((scope) => scopes.includes(scope));
    return user && user.scopes && hasScope();

Use the ScopesGuard as a global guard for all routes (returns true when no scopes are given):

@Module({
  providers: [
      provide: APP_GUARD,
      useClass: ScopesGuard,
export class ApplicationModule {}

And then use it on an endpoint:

@Get('protected')
@UseGuards(AuthGuard('jwt'))
@Scopes('manage_server')
async protected(): Promise<string> {
    return 'Hello Protected World';
                Great, thank you very much, using a custom guard was the solution I came with since I posted the question, but your solution of using a custom decorator is something I really like. Thank you for your time!
– Hammerbot
                Aug 20, 2018 at 16:02
                Nice class for checking scopes Kim!  I did find several minor typos with the class:  1. You're spreading the scopes parameter so @Scopes(['manage_server']) will  raise a compile time warning. I changed (...scopes: string[]) to (scopes: string[])  2. make sure scope includes the variable "scope", not "scopes". (scope => scopes.includes(scope));  Thanks again!
– Leo
                Dec 13, 2018 at 18:14
                @leokwanbt14 Thanks! :-) I have updated the answer with your input. I've left in the spread though because then you can use the decorator as @Scopes('manage_server') instead of @Scopes(['manage_server']) which feels more natural to me.
– Kim Kern
                Dec 14, 2018 at 18:18
                I did exactly the same but context.switchToHttp().getRequest(); is always undefined for me @KimKern
– Yashwanth Kata
                Jul 16, 2021 at 16:32

I tried a slightly different approach, by extending the AuthGuard guard. I wanted to maintain the ability to use different Passport Strategies, so I included a mixin. Feedback is appreciated.

In your Jwt strategy you could simply return the JwtPaylozd so that the user has a scopes attribute. Then the custom AuthGuard looks like this:

import { UnauthorizedException, mixin } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
export function AuthScopes(scopes: string[], type?: string | string[]) {
    return mixin(class ScopesAuth extends AuthGuard(type) {
        protected readonly scopes = scopes;
        handleRequest(err, user, info, context) {
        if (err || !user) {
            throw err || new UnauthorizedException();
        if(!this.scopes.some(s => user.scopes.split(' ').includes(s)))
            throw new UnauthorizedException(`JWT does not possess one of the required scopes (${this.scopes.join(',')})`);
        return user;

You can then use this guard like so:

@Get('protected')
@UseGuards(AuthScopes(['secret:read'], 'jwt'))
async protected(): Promise<string> {
    return 'Hello Protected World';

'jwt' represents the strategy.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.