Skip to main content

client overview

Client-side permission checks for React, Vue, and vanilla JavaScript. Server-driven hydration with sub-millisecond lookups.

How it works

duck-iam ships client libraries for browser permission checks. The recommended pattern is server-driven: generate a PermissionMap on the server, send it to the client, and use it for UI decisions.

Loading diagram...

Every client library supports the same core operations:

  • can(action, resource, resourceId?, scope?) — returns true when the permission is granted
  • cannot(action, resource, resourceId?, scope?) — returns true when the permission is denied

Client checks are synchronous lookups against the pre-computed map. No network requests during checks.


Pick a client

FrameworkDocSubpath
Reactclient/react@gentleduck/iam/client/react
Vueclient/vue@gentleduck/iam/client/vue
Vanilla JSclient/vanilla@gentleduck/iam/client/vanilla

Use the PermissionMap reference for the wire format, key encoding, and buildPermissionKey() helper.


Server-driven pattern

Loading diagram...

  • Security — Permission logic runs on the server where policies and roles are stored. The client only sees the final boolean results.
  • Performance — Client-side checks are instant object lookups. No async, no network, no engine evaluation.
  • Consistency — The server is the single source of truth.
  • Simplicity — The client libraries are thin wrappers around a flat object.

Refreshing permissions

When a user's role changes (promoted, joined an org, feature flag flips), fetch a new permission map from the server and update the client.

React:

// Re-render the server component (Next.js router.refresh())
// or use usePermissions with a refetch trigger
// Re-render the server component (Next.js router.refresh())
// or use usePermissions with a refetch trigger

Vue:

const { update } = useAccess()
const newPerms = await fetch('/api/me/permissions').then((r) => r.json())
update(newPerms)
const { update } = useAccess()
const newPerms = await fetch('/api/me/permissions').then((r) => r.json())
update(newPerms)

Vanilla:

const newPerms = await fetch('/api/me/permissions').then((r) => r.json())
access.update(newPerms) // subscribers are notified automatically
const newPerms = await fetch('/api/me/permissions').then((r) => r.json())
access.update(newPerms) // subscribers are notified automatically

FAQ