Check Abilities

CASL is an isomorphic authorization JavaScript library

View project on GitHub

After abilities are defined, you can use the can method of Ability instance to check the user’s permission for a given action and object.

ability.can('delete', post)

The cannot method is for convenience and performs the opposite check of can

ability.cannot('delete', post)

You can also pass a class or model name instead of instance

ability.can('delete', 'Post')

Important: If an object of conditions exist they will be ignored when checking on a class name, and it will return true. For example:

const ability = AbilityBuilder.define(can => {
  can('read', 'Post', { published: true })
})

ability.can('read', 'Post') // true

Think of it as asking “can the current user read at least one post?”. The user can read a post which has published set to true, so this returns true. If you are doing a class name check, it is important you do another check once an instance becomes available so the object of conditions can be used.

One more handy method is thowUnlessCan, it throws ForbiddenError if user is not able to perform an action on specified object.

async function findPost(req, res) {
  const post = await Post.find({ _id: req.params.id })

  req.ability.throwUnlessCan('read', post)
  res.send(post)
}

Instance checks

By default, CASL is looking for modelName attribute on constructor of the passed object (and fallbacks to constructor name if that is blank). Lets consider example:

class Post {
  constructor(title, published) {
    this.title = title
    this.published = published
  }
}

ability.can('read', new Post({ published: true }))

In this case, ability will check whether rules for Post class is defined and check if user can read this particular instance of Post.

Important: if you use minification for production builds, it will minify class names as well and this example won’t work. For such cases, you can define static modelName attribute on a class.

In this example, ability will check rules for Post and not for Article:

class Article {
  static get modelName() {
    return 'Post'
  }

  constructor(title, published) {
    this.title = title
    this.published = published
  }
}

ability.can('read', new Article({ published: true }))

In case if the default behavior is not satisfied for you, it’s possible to pass custom subjectName option in Ability constructor, which should return passed object name. This may be useful if you want to define actions for RPC procedures (e.g., in CQRS or GraphQL interfaces).

const ability = new Ability([...], {
  subjectName(subject) {
    // implement your logic here which detects subject's name
  }
})

The default logic looks this:

function subjectName(subject) {
  if (!subject || typeof subject === 'string') {
    return subject;
  }

  const Type = typeof subject === 'object' ? subject.constructor : subject;
  return Type.modelName || Type.name;
}