Checking Access
Once grants are defined, you query them. There are a chainable form and a one‑shot form, plus a fail‑closed variant.
Chainable: can() / tryCan()
Section titled “Chainable: can() / tryCan()”const perm = ac.can('user').readAny('article');perm.granted; // booleanperm.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 attributespossession is resolved, not just echoed back: since any ⊇ own, 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');One-shot: check() / checkAsync()
Section titled “One-shot: check() / checkAsync()”When you already have a fulfilled query object:
const perm = ac.check({ role: 'user', resource: 'article', action: 'read:any', context: { /* … */ }});perm.granted;granted vs attributes
Section titled “granted vs attributes”granted— whether access is allowed (≥ 1 non‑negated attribute).attributes— what fields are allowed (glob notation).
ac.grant('u').readAny('post', ['*', '!secret']);ac.can('u').readAny('post').granted; // trueac.can('u').readAny('post').attributes; // ['*', '!secret']
ac.grant('u').createAny('post', []); // explicitly no attributesac.can('u').createAny('post').granted; // falseFiltering the Response
Section titled “Filtering the Response”const perm = ac.can('user').readOwn('account');res.json(perm.filter(account)); // single objectres.json(perm.filter(accounts)); // array → maps over eachAsync Checks
Section titled “Async Checks”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.
Why a Check Might Be Denied
Section titled “Why a Check Might Be Denied”Subscribe to the access event — every
resolved check (granted and denied) carries a reason
(no_grant, condition_failed, ownership_failed, require_failed).