question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Nest JS authorization with CASL doesn't work as expected

See original GitHub issue

Expected behavior Be able to get user info with id equal to my id only (which is saved in JWT token).

Current result I am able to get info about all users with some id.

Used Nest Js docs while creating this solution. Do appreciate your help.

  1. /casl-ability.factory.ts
type Subjects = InferSubjects<typeof User | typeof Role | 'User'> | 'all';
export type AppAbility = Ability<[Action, Subjects]>;

export class CaslAbilityFactory {
  createForUser(userDataFromJWT: JwtAccessTokenInput) {
    const { can, cannot, build } = new AbilityBuilder<
      Ability<[Action, Subjects]>
    >(Ability as AbilityClass<AppAbility>);

    // TESTING THIS CASE
    can(Action.Read, User, {
      id: userDataFromJWT.sub,
    });

    return build({
      detectSubjectType: (item) =>
        item.constructor as ExtractSubjectType<Subjects>,
    });
  }

  private hasRole(roles: unknown[], role: UserRoles): boolean {
    return roles.includes(role);
  }
}
  1. /getUser.policyHandler.ts
export class GetUserPolicyHandler implements IPolicyHandler {
      handle(ability: AppAbility) {
        return ability.can(Action.Read, User);
      }
    }
  1. /types.ts
export enum Action {
  Manage = 'manage',
  Create = 'create',
  Read = 'read',
  Update = 'update',
  Delete = 'delete',
}

export interface IPolicyHandler {
  handle(ability: AppAbility): boolean;
}

type PolicyHandlerCallback = (ability: AppAbility) => boolean;

export type PolicyHandler = IPolicyHandler | PolicyHandlerCallback;
  1. /policies.guard.ts
@Injectable()
export class PoliciesGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private caslAbilityFactory: CaslAbilityFactory,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const policyHandlers =
      this.reflector.get<PolicyHandler[]>(
        CHECK_POLICIES_KEY,
        context.getHandler(),
      ) || [];

    const ctx = GqlExecutionContext.create(context);
    const { user }: { user: JwtAccessTokenInput } = ctx.getContext().req;
    const ability = this.caslAbilityFactory.createForUser(user);

    return policyHandlers.every((handler) =>
      this.execPolicyHandler(handler, ability),
    );
  }

  private execPolicyHandler(handler: PolicyHandler, ability: AppAbility) {
    if (typeof handler === 'function') {
      return handler(ability);
    }
    return handler.handle(ability);
  }
}
  1. /user.resolver.ts
@Resolver(() => User)
export class UserResolver {
  constructor(private readonly userService: UserService) {}

  @Query(() => User, { name: 'user' })
  @UseGuards(PoliciesGuard)
  @CheckPolicies(new GetUserPolicyHandler())
  @UseInterceptors(UserNotExistsByIDInterceptor)
  async findOne(@Args('id', { type: () => Int }) id: number): Promise<User> {
    return await this.userService.findOne(id);
  }
}

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
stalniycommented, Jan 6, 2022
allow(Action.Read, 'User', { id: user.sub });
forbid(Action.Delete, 'User');

change code above to use User class.

allow(Action.Read, User, { id: user.sub });
forbid(Action.Delete, User);

and should work

0reactions
Gleb-Gaidukcommented, Jan 6, 2022

Thanks so much, Sergii, looks like that works as expected. Have a nice day.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Nest JS authorization with CASL doesn't work as expected
EXPECTING: Be able to get user info with id equal to my id only (which is saved in JWT token). CURRENT RESULT: I...
Read more >
Rule with class and conditions doesn't work #430 - GitHub
I tried too of downgrade @casl/ability to version 4.1.6 and the first code (using Post in the rule specification) works as expected.
Read more >
How to Manage User Access in NestJS - YouTube
In this video we'll take a deep dive into integrating CASL ( authorization ABAC library) into the popular NestJS framework.
Read more >
Extensible and secure authorization with Nestjs and CASL
In this session, we add a requirement to our system: a leader can view only invoices in his department. Firstly, let's update the...
Read more >
stalniy-casl/casl - Gitter
If you use bundler on backend code, expect issues :) CASL doesn't use eval ... Hey all, I've got a nestjs app that...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found