Policies
Guards check who the user is; policies check what they can do with a specific resource. A policy defines rules like “users can edit their own posts” or “only admins can delete comments,” keeping authorization logic centralized rather than scattered across handlers.
Defining Policies
Section titled “Defining Policies”import { definePolicy } from '@veloxts/auth';
const PostPolicy = definePolicy('Post', { create: ({ user }) => user.role === 'editor' || user.role === 'admin', update: ({ user, resource }) => resource.authorId === user.id, delete: ({ user, resource }) => resource.authorId === user.id || user.role === 'admin',});Each action is a PolicyActionRef with .actionName, .resourceName, and .check():
PostPolicy.update.actionName // 'update'PostPolicy.update.resourceName // 'Post'PostPolicy.update.check(user, post) // boolean | Promise<boolean>Using .policy() on the Builder
Section titled “Using .policy() on the Builder”The recommended way to enforce policies — checked automatically before the handler runs:
import { procedure } from '@veloxts/velox';import { authenticated } from '@veloxts/auth';
updatePost: procedure() .input(z.object({ id: z.string(), data: UpdatePostSchema })) .guard(authenticated) .use(loadPost) // adds { post: Post } to context .policy(PostPolicy.update) // checked before handler — throws ForbiddenError on failure .mutation(async ({ input, ctx }) => { return ctx.db.post.update({ where: { id: input.id }, data: input.data, }); }),The policy looks up the resource from context by name — PostPolicy looks for ctx.post. Forgetting .use(loadPost) before .policy() produces a TypeScript error when the resource name is a string literal.
Manual Helpers
Section titled “Manual Helpers”For complex conditional logic inside handlers, use can() and cannot():
import { can, cannot } from '@veloxts/auth';
if (await can(ctx.user, 'update', 'Post', post)) { // User can update}
if (await cannot(ctx.user, 'delete', 'Post', post)) { // User cannot delete}Policies vs Guards
Section titled “Policies vs Guards”| Feature | Guards | Policies (.policy()) | Policies (can()/cannot()) |
|---|---|---|---|
| Scope | Request-level | Resource-level | Resource-level |
| Example | ”Is user admin?" | "Can user edit THIS post?" | "Can user edit THIS post?” |
| Runs | Before handler | Before handler | Inside handler |
| Style | Declarative | Declarative | Imperative |
Related Content
Section titled “Related Content”- Guards — Request authorization
- Business Logic — Transactions, events, pipelines
- JWT — Authentication