Use when defining a new role in Bknd authorization system. Covers role properties (implicit_allow, is_default, permissions), permission assignment, role hierarchies, and common role patterns (admin, editor, viewer, anonymous).
npx claudepluginhub cameronapak/bknd-expert --plugin bknd-research-skillsThis skill uses the workspace's default tool permissions.
Define a new role in Bknd's authorization system to control user access.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Define a new role in Bknd's authorization system to control user access.
auth: { enabled: true })guard: { enabled: true })UI steps: Admin Panel > Auth > Roles
Note: Role creation requires code mode. UI only shows existing roles.
Roles require the guard system to be enabled:
import { serve } from "bknd/adapter/bun";
import { em, entity, text } from "bknd";
const schema = em({
posts: entity("posts", { title: text().required() }),
});
serve({
connection: { url: "file:data.db" },
config: {
data: schema.toJSON(),
auth: {
enabled: true,
guard: { enabled: true }, // Required for roles
roles: {
// Roles defined here
},
},
},
});
Create a role with explicit permissions:
{
auth: {
enabled: true,
guard: { enabled: true },
roles: {
viewer: {
implicit_allow: false, // Deny by default
permissions: [
"data.entity.read", // Grant read access only
],
},
},
},
}
| Property | Type | Default | Description |
|---|---|---|---|
implicit_allow | boolean | false | Allow all unless denied |
is_default | boolean | false | Use when user has no role |
permissions | array | [] | Permissions granted to role |
Grant full access with implicit_allow:
{
roles: {
admin: {
implicit_allow: true, // Can do everything
},
},
}
Warning: implicit_allow: true grants ALL permissions. Use only for admin roles.
Grant specific CRUD permissions:
{
roles: {
editor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
// No delete permission
],
},
},
}
Set a role for users without assigned role:
{
roles: {
anonymous: {
is_default: true, // Applied when no role
implicit_allow: false,
permissions: [
"data.entity.read", // Read-only access
],
},
},
}
Note: Only ONE role can have is_default: true.
Assign role to newly registered users:
{
auth: {
enabled: true,
default_role_register: "user", // Role for new registrations
roles: {
user: {
implicit_allow: false,
permissions: ["data.entity.read"],
},
},
},
}
| Permission | Description |
|---|---|
data.entity.read | Read any entity records |
data.entity.create | Create records in any entity |
data.entity.update | Update records in any entity |
data.entity.delete | Delete records from any entity |
data.database.sync | Sync database schema |
data.raw.query | Execute raw SELECT queries |
data.raw.mutate | Execute raw INSERT/UPDATE/DELETE |
{
auth: {
enabled: true,
guard: { enabled: true },
default_role_register: "user",
roles: {
// Full access
admin: {
implicit_allow: true,
},
// Content management
editor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
"data.entity.delete",
],
},
// Create and read
contributor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
],
},
// Authenticated read-only
user: {
implicit_allow: false,
permissions: [
"data.entity.read",
],
},
// Unauthenticated/guest
anonymous: {
is_default: true,
implicit_allow: false,
permissions: [
"data.entity.read",
],
},
},
},
}
{
auth: {
enabled: true,
guard: { enabled: true },
allow_register: false, // Disable self-registration
roles: {
admin: {
implicit_allow: true,
},
member: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
],
},
// No default role - unauthenticated users get NO access
},
},
}
{
roles: {
api_client: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
// No update/delete - API clients create data only
],
},
},
}
Use extended format for allow/deny effects:
{
roles: {
moderator: {
implicit_allow: false,
permissions: [
{ permission: "data.entity.read", effect: "allow" },
{ permission: "data.entity.update", effect: "allow" },
{ permission: "data.entity.delete", effect: "deny" }, // Explicit deny
],
},
},
}
{
options: {
seed: async (ctx) => {
await ctx.app.module.auth.createUser({
email: "admin@example.com",
password: "secure-password",
role: "admin", // Assign admin role
});
},
},
}
{
auth: {
default_role_register: "user", // All registrations get "user" role
},
}
const api = getApi(app);
// Update user's role
await api.data.updateOne("users", userId, {
role: "editor",
});
Test role permissions:
1. Create user with role:
curl -X POST http://localhost:7654/api/auth/password/register \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com", "password": "password123"}'
2. Login and get token:
curl -X POST http://localhost:7654/api/auth/password/login \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com", "password": "password123"}'
3. Test permission (should succeed for read):
curl http://localhost:7654/api/data/posts \
-H "Authorization: Bearer <token>"
4. Test denied permission (should fail for delete if not allowed):
curl -X DELETE http://localhost:7654/api/data/posts/1 \
-H "Authorization: Bearer <token>"
# Returns 403 if delete not in permissions
Problem: User has no role error for unauthenticated users
Fix: Set a default role:
{
roles: {
anonymous: {
is_default: true,
permissions: ["data.entity.read"],
},
},
}
Problem: Unpredictable behavior with multiple is_default: true
Fix: Only ONE role should be default:
{
roles: {
user: { is_default: true }, // Only one!
guest: { /* no is_default */ },
},
}
Problem: Role "admin" not found when assigning
Fix: Define role before referencing:
{
auth: {
roles: {
admin: { implicit_allow: true }, // Define first
},
default_role_register: "admin", // Then reference
},
}
Problem: Roles defined but permissions not enforced
Fix: Enable the guard:
{
auth: {
enabled: true,
guard: { enabled: true }, // Required!
roles: { /* ... */ },
},
}
Problem: Using implicit_allow: true on non-admin roles
Fix: Be explicit about permissions:
// WRONG - too permissive
{
roles: {
editor: { implicit_allow: true },
},
}
// CORRECT - explicit permissions
{
roles: {
editor: {
implicit_allow: false,
permissions: [
"data.entity.read",
"data.entity.create",
"data.entity.update",
],
},
},
}
DO:
implicit_allow: false for non-admin rolesDON'T:
implicit_allow: true for non-admin rolesdata.raw.* permissions to untrusted roles