Skip to content

Checking Access

Once grants are defined, you query them. There are a chainable form and a one‑shot form, plus a fail‑closed variant.

const perm = ac.can('user').readAny('article');
perm.granted; // boolean
perm.attributes; // e.g. ['*', '!secret']
perm.roles; // ['user']
perm.resource; // 'article'
perm.action; // 'read' (bare verb; ':possession' suffix stripped)
perm.possession; // 'any' | 'own' (the possession that actually granted)
perm.filter(data) // data with only the allowed attributes

possession is resolved, not just echoed back: since anyown, a query for own that’s satisfied by an any grant reports 'any' — so you can tell how access was granted. On denial it reflects the requested possession.

Pass context as the second argument (or via .with()):

ac.can('manager', { order }).updateAny('order');
ac.can('manager').with({ order }).updateAny('order');

When you already have a fulfilled query object:

const perm = ac.check({
role: 'user',
resource: 'article',
action: 'read:any',
context: { /* … */ }
});
perm.granted;
  • grantedwhether access is allowed (≥ 1 non‑negated attribute).
  • attributeswhat fields are allowed (glob notation).
ac.grant('u').readAny('post', ['*', '!secret']);
ac.can('u').readAny('post').granted; // true
ac.can('u').readAny('post').attributes; // ['*', '!secret']
ac.grant('u').createAny('post', []); // explicitly no attributes
ac.can('u').createAny('post').granted; // false
const perm = ac.can('user').readOwn('account');
res.json(perm.filter(account)); // single object
res.json(perm.filter(accounts)); // array → maps over each

A check whose applicable grant/gate uses a custom { fn } condition must be resolved with grantedAsync / checkAsync:

const ok = await ac.can('admin', { ip })
.readAny('server').grantedAsync;
const perm = await ac.checkAsync({
role: 'admin', resource: 'server', action: 'read:any', context: { ip }
});

The sync .granted throws ASYNC_REQUIRED for such checks (or, under tryCan(), denies). See Async & Custom Functions.

Subscribe to the access event — every resolved check (granted and denied) carries a reason (no_grant, condition_failed, ownership_failed, require_failed).