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.
Every client library supports the same core operations:
can(action, resource, resourceId?, scope?)- returnstruewhen the permission is grantedcannot(action, resource, resourceId?, scope?)- returnstruewhen the permission is denied
Client checks are synchronous lookups against the pre-computed map. No network requests during checks.
Pick a client
| Framework | Doc | Subpath |
|---|---|---|
| React | client/react | @gentleduck/iam/client/react |
| Vue | client/vue | @gentleduck/iam/client/vue |
| Vanilla JS | client/vanilla | @gentleduck/iam/client/vanilla |
Use the PermissionMap reference for the wire format, key encoding, and iamBuildPermissionKey() helper.
Server-driven pattern
- 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
Vue:
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