Skip to content
Warlock.js v4.2.11

API reference

Everything @warlock.js/access exports. All check functions are also available on the access facade object (access.can, access.authorize, …).

ExportSignatureNotes
can(user, permission, ctx?) => Promise<boolean>grant (and policy, if a resource is in ctx)
cannot(user, permission, ctx?) => Promise<boolean>inverse of can
canAll(user, permissions[], ctx?) => Promise<boolean>every permission; short-circuits
canAny(user, permissions[], ctx?) => Promise<boolean>any permission; short-circuits
authorize(user, permission, ctx?) => Promise<void>throws ForbiddenError (403) on deny
authorizeAll(user, permissions[], ctx?) => Promise<void>throws unless all pass
authorizeAny(user, permissions[], ctx?) => Promise<void>throws unless any passes
ExportSignature
hasRole(user, role, tenant?) => Promise<boolean>
hasAnyRole(user, roles[], tenant?) => Promise<boolean>
hasAllRoles(user, roles[], tenant?) => Promise<boolean>
ExportSignatureNotes
access.flush / flush(user, tenant?) => Promise<void>drop the cached role/permission set after you mutate role rows

Role assignment is not in the package — it lives on the ejected UserRole model in your app (UserRole.assign / UserRole.revoke). Call those, then access.flush(user, tenant).

ExportSignature
definePolicy(permission, (user, resource, ctx) => boolean | Promise<boolean>) => void
ExportSignatureNotes
gate(permission) => Middlewareclass-level route gate
gateAny(permissions[]) => Middlewarepasses on any
gateAll(permissions[]) => Middlewarepasses on all

Stack these after authMiddleware (they read request.user).

ExportNotes
AccessResolverthe contract — resolveRoles + resolvePermissions + optional resolveTenant
DefaultAccessResolvernew (roles, readRoles?) — fixed inline catalog; reads roles off the user model

resolveTenant?(user: Auth): string \| undefined is the optional third method — implement it to supply the ambient tenant when a check doesn’t pass one. It receives the user, so derive the tenant from there (e.g. user.get("organization_id")) — safer than trusting client request input. The DB-backed resolver and the role tables (Role, UserRole) are ejected into your app (npx warlock add access), not exported by the package.

ExportNotes
AccessErrorCodesForbidden = "EC100"
AccessConfigErrorthrown loudly on misconfig (e.g. no resolver) — not a silent deny
AccessConfigurationsconfig.access.* shape — { resolver, cache?: { ttl } }
AccessContextcheck context — reserved resource / tenant + free-form
PolicyContextwhat a policy receives — tenant, hasRole, hasPermission, free-form
PolicyFn(user, resource, ctx) => boolean | Promise<boolean>
RolesMapRecord<string, string[]>
  • can / authorize = grant AND (no policy OR policy passes). A policy runs only when ctx.resource is supplied.
  • Wildcards: * (super-grant), orders.* (prefix, nested-aware — but not the bare orders), exact.
  • Fails closed — any error resolving a decision denies and logs.
  • The cache is best-effort — a cache failure degrades to the resolver, never denies.
  • Tenant = ctx.tenant ?? resolver.resolveTenant?.(user) ?? undefined.
  • A missing resolver throws AccessConfigError (loud) at boot instead of denying.