I'm struggling with the error (TypeError: Cannot read properties of undefined (reading 'roles') when i try to implement RBAC using nest here's my code. Im unable to sort out the error and im struggling with this error from 2 weeks. Please help me in fixing this error. Thanks in advance. enter image description here my auth.controller.ts code
import { Controller, Post, UseGuards, Request, Get } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { Roles } from './decorators/roles.decorator';
import { Role } from './enums/role.enum';
import { JwtAuthGuard } from './guards/jwt-auth.guard';
import { LocalAuthGuard } from './guards/local-auth.guard';
import { RolesGuard } from './guards/roles.guard';
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
@UseGuards(LocalAuthGuard)
@Post('/login')
async validate(@Request() req) {
//console.log(req);
return this.authService.login(req.user);
}
@Get('/user')
@Roles(Role.User)
@UseGuards(JwtAuthGuard, RolesGuard)
getProfile(@Request() req) {
return req.user;
}
}
my role.gaurd.ts code
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Role } from 'src/auth/enums/role.enum';
import { ROLES_KEY } from 'src/auth/decorators/roles.decorator';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
console.log("user",user)
return requiredRoles.some((role) => user.roles?.includes(role));
}
}
role.decorator.ts
import { SetMetadata } from '@nestjs/common';
import { Role } from '../enums/role.enum';
export const ROLES_KEY = 'roles';
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
user.service.ts code
import { HttpException, HttpStatus, Injectable, Post, UseGuards } from '@nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { User, UserDocument } from './user.schema';
import { CreateUserDTO } from './create-user.dto';
import { FilterUserDTO } from './filter-user.dto';
import * as bcrypt from 'bcrypt';
@Injectable()
export class UserService {
constructor(
@InjectModel('User') private readonly userModel: Model<UserDocument>,
) {}
async getFilteredUsers(filterUserDTO: FilterUserDTO): Promise<User[]> {
const { category, search } = filterUserDTO;
let users = await this.getAllUsers();
if (search) {
users = users.filter(
(user) =>
user.firstName.includes(search) ||
user.lastName.includes(search) ||
user.email.includes(search),
);
}
/* if (category) {
users = users.filter((user) => user.firstName === );
} */
return users;
}
async getAllUsers(): Promise<User[]> {
const users = await this.userModel.find().exec();
return users;
}
async getUser(email: string): Promise<User> {
const user = await this.userModel.findOne({ email: email }).exec();
return user;
}
async addUser(createUserDTO: CreateUserDTO): Promise<User> {
const newUser = await this.userModel.create(createUserDTO);
newUser.password = await bcrypt.hash(newUser.password, 10);
return newUser.save();
}
async updateUser(id: string, createUserDTO: CreateUserDTO): Promise<User> {
const updatedUser = await this.userModel.findByIdAndUpdate(
id,
createUserDTO,
{ new: true },
);
return updatedUser;
}
async deleteUser(email: string): Promise<any> {
const deletedUser = await this.userModel.findOneAndRemove({ email: email });
return deletedUser;
}
}
Im trying to implement role based authentication for my routes and i've followed the documentation and tutorials and still i was stuck with this error
I think the issue might be with the request itself. The guard for roles read the request.user object to find out the user roles. This, in the example from Nest page, is parsed in by the first jwtGuard and saved to the request.user.
The error seems to refer that users is undefined, so it does not have the 'roles' property to find, thus type error. Check if the user is correctly being added by the JWT guard and that yout JWT does have a {roles: ['asd']}