zxkit

@zxkit/authz

Typed authorization for roles, permissions, and routes.

Your app already knows who the user is. This decides what they can see and run — once, with the same types on the server, the client, and the Next.js proxy.

bun add @zxkit/authzDocumentationnpm

Define once

permissions.ts

One catalog of resources and actions. Everything else is typed from it.

import { definePermissions } from '@zxkit/authz'

export const permissions = definePermissions({
  order: ['read', 'create', 'update', 'delete'],
  invoice: ['read', 'export'],
  settings: ['manage'],
})

Server

authz.ts

Session, adapter, and cache in one helper. protect wraps any server action.

import { createAuthz, redisCache } from '@zxkit/authz'
import { prismaAuthzAdapter } from '@zxkit/authz/prisma'

export const authz = createAuthz({
  permissions,
  getSession,
  adapter: prismaAuthzAdapter(db),
  cache: redisCache(redis, { ttl: 60 * 30 }),
})

export const deleteOrder = authz.protect(
  { order: ['delete'] },
  async ({ user }, orderId: string) => {
    return orders.delete({ orderId, deletedBy: user.id })
  }
)

Client

authz-client.ts

Typed guards and hooks. No fetching — they read the snapshot you already loaded.

'use client'

import { createAuthzClient } from '@zxkit/authz/client'
import { permissions } from './permissions'

export const { AuthzProvider, Can, Guard, useCan } =
  createAuthzClient(permissions)

Routes

proxy.ts

The same route definitions protect the whole app before anything renders.

import { createAuthzProxy } from '@zxkit/authz/next'

export const proxy = createAuthzProxy({
  authz,
  auth: { signIn: '/login', afterSignIn: '/hub', forbidden: '/hub' },
  public: ['/'],
  guestOnly: ['/login'],
  protected: [{ matcher: '/hub/:path*', routes }],
})
Typed permissions
Resources and actions autocomplete. Invalid ones fail to compile.
Roles in your database
The catalog lives in code; roles and assignments live in Prisma.
Guards everywhere
Can, Guard, and hooks on the client. require and protect on the server.
Next.js proxy
Protected zones, guest-only and public routes from the same definitions.
Cached snapshots
Memory or Redis, invalidated on role mutations, resilient to outages.