Static
Static mode is Arkos's code-based permission system. Roles are assigned on the User model as an enum field, and permissions are declared via ArkosPolicy (v1.6+, recommended) or .auth.ts files (v1.1+, still supported). Arkos enforces them automatically across all routes.
Before using Static mode make sure you have authentication configured. See Authentication Setup.
User Model
Static mode requires a role or roles enum field on your User model:
enum UserRole {
Admin
Editor
User
}
model User {
// ... required Arkos fields
role UserRole @default(User) // single role
// roles UserRole[] // multiple roles
}See the full required User model at User Model Authentication Setup.
ArkosPolicy
ArkosPolicy is the recommended API introduced in v1.6. It provides a fluent interface for defining permissions, works for any module (Prisma models, auth, file upload, or custom), and supports imperative can* checks for Fine-Grained Access Control.
Defining a Policy
import { ArkosPolicy } from "arkos";
const postPolicy = ArkosPolicy("post")
.rule("Create", { roles: ["Admin", "Editor"], name: "Create Post", description: "Create new posts" })
.rule("Update", { roles: ["Admin", "Editor"], name: "Update Post" })
.rule("Delete", { roles: ["Admin"], name: "Delete Post" })
.rule("View", { roles: ["*"] }); // all authenticated users
export default postPolicy;.rule(action, rule) accepts:
| Value | Behavior |
|---|---|
{ roles: ["*"] } | All authenticated users |
{ roles: [...], name?, description? } | Role-restricted |
["Admin", "Editor"] | Shorthand for roles array |
Using Permissions in Routes
Permissions wire the same way whether you're on a custom route or a built-in one. For built-in routes (Prisma model, auth, file upload) use a Route Hook alongside your ArkosRouter export.
import { ArkosRouter } from "arkos";
import postPolicy from "@/src/modules/post/post.policy";
import postController from "@/src/modules/post/post.controller";
const router = ArkosRouter();
router.post(
{ path: "/api/posts", authentication: postPolicy.Create },
postController.createOne
);
router.get(
{ path: "/api/posts", authentication: postPolicy.View },
postController.findMany
);
export default router;import { ArkosRouter, RouteHook } from "arkos";
import postPolicy from "@/src/modules/post/post.policy";
export const hook: RouteHook = {
createOne: { authentication: postPolicy.Create },
findMany: { authentication: postPolicy.View },
updateOne: { authentication: postPolicy.Update },
deleteOne: { authentication: postPolicy.Delete },
};
const router = ArkosRouter();
export default router;RouteHook is the new name for export const config: RouterConfig. If you have existing code using the old name it still works but will log a deprecation warning. See Route Hook for full details.
Using Permissions in Express Router
If you're using a plain Express Router instead of ArkosRouter, wire authentication manually via authService:
import { Router } from "express";
import { authService } from "arkos/services";
import postPolicy from "@/src/modules/post/post.policy";
import postController from "@/src/modules/post/post.controller";
const router = Router();
// login required only
router.get("/api/posts", authService.authenticate, postController.findMany);
// role-based — v1.6+
router.post(
"/api/posts",
authService.authenticate,
authService.authorize("Create", "post", postPolicy.Create),
postController.createOne
);| Method | Signature | Version |
|---|---|---|
authService.authenticate | middleware | all |
authService.authorize | (action, resource, rule) | v1.6+ |
authService.handleAccessControl | (action, resource, accessControl) | before v1.6 |
Imperative Checks
ArkosPolicy exposes can* methods for use inside services, interceptors, or any custom logic — this is the foundation of Fine-Grained Access Control:
import postPolicy from "@/src/modules/post/post.policy";
if (await postPolicy.canDelete(req.user)) {
// proceed
}Imperative checks in fine-grained access control also work with auth config files. See the full guide at Fine-Grained Access Control.
CLI Generation (v1.6+)
arkos generate policy --module post
# or
arkos g p -m postAuth Config Files
.auth.ts auto-loading is deprecated as of v1.6 and will be removed in v2.0. New projects should use ArkosPolicy. Existing projects can migrate gradually — see the migration guide.
.auth.ts files have been the standard since v1.0 and remain fully supported. They define authenticationControl (who needs to be logged in) and accessControl (which roles can act) separately.
Creating an Auth File
arkos generate auth-configs --module post
# or
arkos g a -m postThis generates src/modules/post/post.auth.ts:
import { AuthConfigs } from "arkos/auth";
export const postAccessControl = {
Create: {
roles: ["Admin", "Editor"],
name: "Create Post",
description: "Permission to create new post records",
},
Update: {
roles: ["Admin", "Editor"],
name: "Update Post",
description: "Permission to update existing post records",
},
Delete: {
roles: ["Admin"],
name: "Delete Post",
description: "Permission to delete post records",
},
View: {
roles: ["*"],
name: "View Post",
description: "Permission to view post records",
},
} as const satisfies AuthConfigs["accessControl"];
export const postAuthenticationControl = {
Create: true,
Update: true,
Delete: true,
View: true,
};
const postAuthConfigs: AuthConfigs = {
authenticationControl: postAuthenticationControl,
accessControl: postAccessControl,
};
export default postAuthConfigs;Auth Config File Structure
authenticationControl — whether a route requires login:
| Value | Behavior |
|---|---|
true | Login required |
false | Public — no authentication |
accessControl — which roles can act:
| Format | Example |
|---|---|
| Simple | ["Admin", "Editor"] |
| Detailed | { roles: [...], name: "...", description: "..." } |
| All authenticated | ["*"] |
Using Auth Config Files in Routes
The same auth config file works on both custom and built-in routes. For built-in routes use a Route Hook alongside your ArkosRouter export.
import { ArkosRouter } from "arkos";
import postAuthConfigs from "@/src/modules/post/post.auth";
import postController from "@/src/modules/post/post.controller";
const router = ArkosRouter();
// login required only
router.get(
{
path: "/api/posts",
authentication: true,
},
postController.findMany
);
// role-based
router.post(
{
path: "/api/posts",
authentication: {
resource: "post",
action: "Create",
rule: postAuthConfigs.accessControl.Create,
},
},
postController.createOne
);
export default router;import { ArkosRouter, RouteHook } from "arkos";
import postAuthConfigs from "@/src/modules/post/post.auth";
export const hook: RouteHook = {
createOne: {
authentication: {
resource: "post",
action: "Create",
rule: postAuthConfigs.accessControl.Create,
},
},
deleteOne: {
authentication: {
resource: "post",
action: "Delete",
rule: postAuthConfigs.accessControl.Delete,
},
},
};
const router = ArkosRouter();
export default router;RouteHook is the new name for export const config: RouterConfig. If you have existing code using the old name it still works but will log a deprecation warning. See Route Hook for full details.
Using Auth Config Files in Express Router
import { Router } from "express";
import { authService } from "arkos/services";
import postAuthConfigs from "@/src/modules/post/post.auth";
import postController from "@/src/modules/post/post.controller";
const router = Router();
// login required only
router.get("/api/posts", authService.authenticate, postController.findMany);
// role-based — v1.6+
router.post(
"/api/posts",
authService.authenticate,
authService.authorize("Create", "post", postAuthConfigs.accessControl.Create),
postController.createOne
);
// role-based — before v1.6
router.post(
"/api/posts",
authService.authenticate,
authService.handleAccessControl("Create", "post", postAuthConfigs.accessControl),
postController.createOne
);Auth Actions Discovery
Both ArkosPolicy and .auth.ts feed the /api/auth-actions endpoint — used by frontends to discover available permissions:
[
{
"resource": "post",
"action": "Create",
"roles": ["Admin", "Editor"],
"name": "Create Post",
"description": "Permission to create new post records"
}
]Export them to a file for frontend integration:
arkos export auth-action
arkos export auth-action --overwrite
arkos export auth-action --path src/constantsSee CLI reference for full options.