Guard says user is undefined in NestJS

Viewed 374
@UseGuards(JwtAccessTokenAuthGuard)
@ApiBearerAuth()
@SetMetadata('roles', Role.ADMIN)
@UseGuards(RolesGuard)
@Post('/add/card')
addCard(@Body() addCardDto: AddCardDto) {
  return this.storeService.addCard(addCardDto);
}

This is the RoleGuard

canActivate(context: ExecutionContext): boolean {
  const roles = this.reflector.get<string[]>('roles', context.getHandler());
  if (!roles) {
    return true;
  }
  const user = context.switchToHttp().getRequest().user;
  return this.matchRoles(roles, user.user_type);
}

In this, the request object has user in the body or inside the function addCard but not in the RoleGuard. Their it says undefined. Why so? In the JwtAccessTokenGuard I returned the user property.

I want to check it inside the Guard and not in function. What am I doing wrong.

2 Answers

When using two of the same decorators, the order, if I recall, is the lowest decorator in the code first, then the highest one. In this case, why not just merge the two @UseGuards() to be a single decorator like @UseGuards(JwtAccessTokenAuthGuard, RolesGuard) so that you're certain of what order the guards will be ran in as described in the docs

In order to get the user in the guard by this method:

const user = context.switchToHttp().getRequest().user;

You should return the user object in the local strategy. That attaches the user object to the request object. The body has nothing to do with the user object. So, your local.strategy.ts should be something like this:

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super({ usernameField: 'email' });
  }

  async validate(email: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(email, password);

    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

For more info, see here.

Related