Define policies once, get database filters, UI guards, and API protection automatically — for both JavaScript and TypeScript.
// Define policies once
const policy = definePolicy({
rules: [{
action: 'post.edit',
effect: 'allow',
when: ({ subject, resource }) =>
subject.id === resource.authorId
}]
})
// Use everywhere
const canEdit = policy.check(
'post.edit',
{ subject: user, resource: post }
)
const decision = policy.checkDetailed(
'post.edit',
{ subject: user, resource: post }
)
Eliminate entire classes of authorization bugs through compile-time validation and automated tenant isolation.
Write policies once, get type-safe API guards, database filters, and UI components automatically.
Drop-in support for Prisma, Next.js, React, Express, and any TypeScript application.
Battle-tested in high-scale applications with sub-millisecond overhead and comprehensive error handling.
Clear error messages, visual policy debugging, and documentation that makes security approachable.
Automatic tenant isolation prevents cross-tenant data leaks without manual validation code.
Traditional authorization approaches scatter security logic across your codebase:
// Scattered checks everywhere - easy to forget or get wrong
if (user.role !== 'admin' && user.tenantId !== post.tenantId) {
throw new Error('Access denied')
}
if (!canUserEditPost(user, post)) {
throw new Error('Cannot edit')
}
// Repeated in 100+ places across your app...
Result
Authorization bugs in production, security vulnerabilities, and frustrated developers.
Define policies once, enforce everywhere automatically:
// Define once - centralized and type-safe
const policy = definePolicy({
byAction: {
'post.edit': [{
effect: 'allow',
when: ({ subject, resource }) =>
subject.id === resource.authorId || subject.role === 'admin'
}]
}
})
// Use everywhere - automatic enforcement
const decision = policy.checkDetailed('post.edit', { subject: user, resource: post })
// Use decision results for authorization
if (!decision.allow) {
throw new Error(decision.reason || 'Access denied')
}
// Apply field masking using readMask
const posts = await prisma.post.findMany({
// Apply any filtering based on decision attributes
where: decision.attrs || {}
})
Result
Security bugs become impossible, not just unlikely.