.agents/skills/bknd-create-role/SKILL.md
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 skillsauth add cameronapak/freedom-stack-v3 bknd-create-roleInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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: "[email protected]",
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": "[email protected]", "password": "password123"}'
2. Login and get token:
curl -X POST http://localhost:7654/api/auth/password/login \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "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 rolesdevelopment
Use btca (Better Context App) to efficiently query and learn from the bknd backend framework. Use when working with bknd for (1) Understanding data module and schema definitions, (2) Implementing authentication and authorization, (3) Setting up media file handling, (4) Configuring adapters (Node, Cloudflare, etc.), (5) Learning from bknd source code and examples, (6) Debugging bknd-specific issues
development
Use when configuring webhook integrations in Bknd. Covers receiving incoming webhooks via HTTP triggers, sending outgoing webhooks with FetchTask, event-triggered webhooks on data changes, signature verification, retry patterns, and async processing.
development
Use when encountering Bknd errors, getting error messages, something not working, or needing quick fixes. Covers error code reference, quick solutions, and common mistake patterns.
tools
Use when writing tests for Bknd applications, setting up test infrastructure, creating unit/integration tests, or testing API endpoints. Covers in-memory database setup, test helpers, mocking, and test patterns.