Claude-skill-registry bknd-create-role

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).

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/bknd-create-role" ~/.claude/skills/majiayu000-claude-skill-registry-bknd-create-role && rm -rf "$T"
manifest: skills/data/bknd-create-role/SKILL.md
source content

Create Role

Define a new role in Bknd's authorization system to control user access.

Prerequisites

  • Bknd project initialized with code-first configuration
  • Auth enabled (
    auth: { enabled: true }
    )
  • Guard enabled for authorization (
    guard: { enabled: true }
    )

When to Use UI Mode

  • Viewing existing roles
  • Quick toggle of role settings

UI steps: Admin Panel > Auth > Roles

Note: Role creation requires code mode. UI only shows existing roles.

When to Use Code Mode

  • Creating new roles
  • Setting role permissions
  • Configuring default roles
  • Setting up role hierarchies

Code Approach

Step 1: Enable Guard

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
      },
    },
  },
});

Step 2: Define a Basic Role

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
        ],
      },
    },
  },
}

Role Properties

PropertyTypeDefaultDescription
implicit_allow
boolean
false
Allow all unless denied
is_default
boolean
false
Use when user has no role
permissions
array
[]
Permissions granted to role

Step 3: Create Admin Role (Full Access)

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.

Step 4: Create Editor Role (Partial Access)

Grant specific CRUD permissions:

{
  roles: {
    editor: {
      implicit_allow: false,
      permissions: [
        "data.entity.read",
        "data.entity.create",
        "data.entity.update",
        // No delete permission
      ],
    },
  },
}

Step 5: Create Default Role

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
.

Step 6: Set Registration Role

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"],
      },
    },
  },
}

Available Permissions

PermissionDescription
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

Common Role Patterns

Multi-Tier Access System

{
  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",
        ],
      },
    },
  },
}

Closed System (No Public Access)

{
  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
    },
  },
}

API Consumer Role

{
  roles: {
    api_client: {
      implicit_allow: false,
      permissions: [
        "data.entity.read",
        "data.entity.create",
        // No update/delete - API clients create data only
      ],
    },
  },
}

Permission Effects

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
      ],
    },
  },
}

Role Assignment

Assign During User Creation (Seed)

{
  options: {
    seed: async (ctx) => {
      await ctx.app.module.auth.createUser({
        email: "admin@example.com",
        password: "secure-password",
        role: "admin",  // Assign admin role
      });
    },
  },
}

Assign During Registration

{
  auth: {
    default_role_register: "user",  // All registrations get "user" role
  },
}

Update User Role (API)

const api = getApi(app);

// Update user's role
await api.data.updateOne("users", userId, {
  role: "editor",
});

Verification

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

Common Pitfalls

No Default Role

Problem:

User has no role
error for unauthenticated users

Fix: Set a default role:

{
  roles: {
    anonymous: {
      is_default: true,
      permissions: ["data.entity.read"],
    },
  },
}

Multiple Default Roles

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 */ },
  },
}

Role Not Found

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
  },
}

Guard Not Enabled

Problem: Roles defined but permissions not enforced

Fix: Enable the guard:

{
  auth: {
    enabled: true,
    guard: { enabled: true },  // Required!
    roles: { /* ... */ },
  },
}

Implicit Allow Overuse

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",
      ],
    },
  },
}

DOs and DON'Ts

DO:

  • Enable guard when using roles
  • Use
    implicit_allow: false
    for non-admin roles
  • Set one default role for unauthenticated access
  • Define roles before referencing them
  • Test each role's permissions after creation

DON'T:

  • Use
    implicit_allow: true
    for non-admin roles
  • Set multiple roles as default
  • Forget to enable guard
  • Grant
    data.raw.*
    permissions to untrusted roles
  • Assume roles work without guard enabled

Related Skills

  • bknd-setup-auth - Initialize authentication system
  • bknd-assign-permissions - Configure detailed permissions with policies
  • bknd-row-level-security - Implement row-level access control
  • bknd-protect-endpoint - Secure specific endpoints
  • bknd-public-vs-auth - Configure public vs authenticated access