bknd-setup-auth

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Setup Authentication

身份验证配置

Initialize and configure the Bknd authentication system with strategies, JWT, cookies, and roles.
初始化并配置Bknd身份验证系统,包含策略、JWT、Cookie和角色设置。

Prerequisites

前置条件

  • Bknd project initialized
  • Code-first configuration (auth config is code-only)
  • For OAuth: provider credentials (client ID, client secret)
  • 已初始化Bknd项目
  • 代码优先配置(身份验证配置仅支持代码方式)
  • 若使用OAuth:需准备服务商凭证(客户端ID、客户端密钥)

When to Use UI Mode

何时使用UI模式

  • Viewing current auth configuration
  • Toggling strategies on/off
  • Testing auth endpoints via admin panel
UI steps: Admin Panel > Auth > Settings
Note: Full auth configuration requires code mode. UI only shows/toggles existing settings.
  • 查看当前身份验证配置
  • 开启/关闭验证策略
  • 通过管理面板测试身份验证端点
UI操作步骤: 管理面板 > 身份验证 > 设置
注意: 完整的身份验证配置需要使用代码模式,UI仅能查看或切换已有的设置。

When to Use Code Mode

何时使用代码模式

  • Initial authentication setup
  • Configuring JWT secrets and expiry
  • Setting up password hashing
  • Defining roles and permissions
  • Production security hardening
  • 身份验证初始设置
  • 配置JWT密钥和过期时间
  • 设置密码哈希规则
  • 定义角色与权限
  • 生产环境安全加固

Code Approach

代码配置方法

Step 1: Enable Auth with Minimal Config

步骤1:通过最简配置启用身份验证

Start with basic password authentication:
typescript
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,
    },
  },
});
This enables:
  • Password strategy (default)
  • Auto-created
    users
    entity
  • JWT-based sessions
  • /api/auth/*
    endpoints
从基础密码身份验证开始:
typescript
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,
    },
  },
});
此配置将启用:
  • 密码验证策略(默认)
  • 自动创建
    users
    实体
  • 基于JWT的会话管理
  • /api/auth/*
    系列端点

Step 2: Configure JWT Settings

步骤2:配置JWT设置

JWT tokens authenticate API requests. Configure for security:
typescript
{
  auth: {
    enabled: true,
    jwt: {
      secret: process.env.JWT_SECRET,  // Required in production
      alg: "HS256",                     // Algorithm: HS256, HS384, HS512
      expires: 604800,                  // Expiry in seconds (7 days)
      issuer: "my-app",                 // Optional issuer claim
      fields: ["id", "email", "role"],  // Fields included in token
    },
  },
}
JWT options:
OptionTypeDefaultDescription
secret
string
""
Signing secret (256-bit minimum for production)
alg
string
"HS256"
Algorithm: HS256, HS384, HS512
expires
number-Token expiry in seconds
issuer
string-Token issuer claim (iss)
fields
string[]
["id", "email", "role"]
User fields in payload
JWT令牌用于验证API请求,需从安全角度进行配置:
typescript
{
  auth: {
    enabled: true,
    jwt: {
      secret: process.env.JWT_SECRET,  // 生产环境必填
      alg: "HS256",                     // 加密算法:HS256、HS384、HS512
      expires: 604800,                  // 过期时间(秒),此处为7天
      issuer: "my-app",                 // 可选的签发者声明
      fields: ["id", "email", "role"],  // 令牌中包含的用户字段
    },
  },
}
JWT选项说明:
选项类型默认值说明
secret
字符串
""
签名密钥(生产环境至少256位)
alg
字符串
"HS256"
加密算法:HS256、HS384、HS512
expires
数字-令牌过期时间(秒)
issuer
字符串-令牌签发者声明(iss)
fields
字符串数组
["id", "email", "role"]
令牌载荷中包含的用户字段

Step 3: Configure Cookie Settings

步骤3:配置Cookie设置

Auth cookies store JWT tokens for browser sessions:
typescript
{
  auth: {
    enabled: true,
    jwt: { secret: process.env.JWT_SECRET },
    cookie: {
      secure: true,           // HTTPS only (set false for local dev)
      httpOnly: true,         // Block JavaScript access
      sameSite: "lax",        // CSRF protection: "strict" | "lax" | "none"
      expires: 604800,        // Cookie expiry in seconds (7 days)
      path: "/",              // Cookie path scope
      renew: true,            // Auto-extend on requests
      pathSuccess: "/",       // Redirect after login
      pathLoggedOut: "/",     // Redirect after logout
    },
  },
}
Cookie options:
OptionTypeDefaultDescription
secure
boolean
true
HTTPS-only flag
httpOnly
boolean
true
Block JS access
sameSite
string
"lax"
CSRF protection
expires
number
604800
Expiry in seconds
renew
boolean
true
Auto-extend expiry
pathSuccess
string
"/"
Post-login redirect
pathLoggedOut
string
"/"
Post-logout redirect
身份验证Cookie用于在浏览器会话中存储JWT令牌:
typescript
{
  auth: {
    enabled: true,
    jwt: { secret: process.env.JWT_SECRET },
    cookie: {
      secure: true,           // 仅HTTPS环境启用(本地开发设为false)
      httpOnly: true,         // 禁止JavaScript访问
      sameSite: "lax",        // CSRF防护:"strict" | "lax" | "none"
      expires: 604800,        // Cookie过期时间(秒),此处为7天
      path: "/",              // Cookie作用路径
      renew: true,            // 请求时自动延长过期时间
      pathSuccess: "/",       // 登录成功后重定向路径
      pathLoggedOut: "/",     // 登出后重定向路径
    },
  },
}
Cookie选项说明:
选项类型默认值说明
secure
布尔值
true
仅HTTPS环境生效标志
httpOnly
布尔值
true
禁止JavaScript访问
sameSite
字符串
"lax"
CSRF防护设置
expires
数字
604800
过期时间(秒)
renew
布尔值
true
自动延长过期时间
pathSuccess
字符串
"/"
登录成功后重定向路径
pathLoggedOut
字符串
"/"
登出后重定向路径

Step 4: Configure Password Strategy

步骤4:配置密码策略

Set up password hashing and requirements:
typescript
{
  auth: {
    enabled: true,
    jwt: { secret: process.env.JWT_SECRET },
    strategies: {
      password: {
        type: "password",
        enabled: true,
        config: {
          hashing: "bcrypt",   // "plain" | "sha256" | "bcrypt"
          rounds: 4,           // bcrypt rounds (1-10)
          minLength: 8,        // Minimum password length
        },
      },
    },
  },
}
Hashing options:
OptionSecurityPerformanceUse Case
plain
NoneFastestDevelopment only, never production
sha256
GoodFastDefault, suitable for most cases
bcrypt
BestSlowerRecommended for production
设置密码哈希规则和复杂度要求:
typescript
{
  auth: {
    enabled: true,
    jwt: { secret: process.env.JWT_SECRET },
    strategies: {
      password: {
        type: "password",
        enabled: true,
        config: {
          hashing: "bcrypt",   // 哈希算法:"plain" | "sha256" | "bcrypt"
          rounds: 4,           // bcrypt加密轮次(1-10)
          minLength: 8,        // 密码最小长度
        },
      },
    },
  },
}
哈希选项对比:
选项安全性性能使用场景
plain
最快仅用于开发环境,绝对禁止在生产环境使用
sha256
良好较快默认选项,适用于大多数场景
bcrypt
最高较慢生产环境推荐使用

Step 5: Define Roles

步骤5:定义角色

Configure roles for authorization:
typescript
{
  auth: {
    enabled: true,
    jwt: { secret: process.env.JWT_SECRET },
    roles: {
      admin: {
        implicit_allow: true,  // Can do everything
      },
      editor: {
        implicit_allow: false,
        permissions: [
          { permission: "data.posts.read", effect: "allow" },
          { permission: "data.posts.create", effect: "allow" },
          { permission: "data.posts.update", effect: "allow" },
        ],
      },
      user: {
        implicit_allow: false,
        is_default: true,  // Default role for new registrations
        permissions: [
          { permission: "data.posts.read", effect: "allow" },
        ],
      },
    },
    default_role_register: "user",  // Role assigned on registration
  },
}
配置用于授权的角色:
typescript
{
  auth: {
    enabled: true,
    jwt: { secret: process.env.JWT_SECRET },
    roles: {
      admin: {
        implicit_allow: true,  // 拥有全部权限
      },
      editor: {
        implicit_allow: false,
        permissions: [
          { permission: "data.posts.read", effect: "allow" },
          { permission: "data.posts.create", effect: "allow" },
          { permission: "data.posts.update", effect: "allow" },
        ],
      },
      user: {
        implicit_allow: false,
        is_default: true,  // 新注册用户的默认角色
        permissions: [
          { permission: "data.posts.read", effect: "allow" },
        ],
      },
    },
    default_role_register: "user",  // 注册时分配的默认角色
  },
}

Step 6: Configure Registration

步骤6:配置注册功能

Control user self-registration:
typescript
{
  auth: {
    enabled: true,
    allow_register: true,           // Enable/disable registration
    default_role_register: "user",  // Role for new users
    entity_name: "users",           // User entity name (default: "users")
    basepath: "/api/auth",          // Auth API base path
  },
}
控制用户自助注册的相关设置:
typescript
{
  auth: {
    enabled: true,
    allow_register: true,           // 启用/禁用注册功能
    default_role_register: "user",  // 新用户的默认角色
    entity_name: "users",           // 用户实体名称(默认:"users")
    basepath: "/api/auth",          // 身份验证API的基础路径
  },
}

Full Production Example

完整生产环境示例

Complete auth setup with security best practices:
typescript
import { serve, type BunBkndConfig } from "bknd/adapter/bun";
import { em, entity, text, date } from "bknd";

const schema = em({
  users: entity("users", {
    email: text().required().unique(),
    name: text(),
    avatar: text(),
    created_at: date({ default_value: "now" }),
  }),
  posts: entity("posts", {
    title: text().required(),
    content: text(),
  }),
});

type Database = (typeof schema)["DB"];
declare module "bknd" {
  interface DB extends Database {}
}

const config: BunBkndConfig = {
  connection: { url: process.env.DB_URL || "file:data.db" },
  config: {
    data: schema.toJSON(),
    auth: {
      enabled: true,
      basepath: "/api/auth",
      entity_name: "users",
      allow_register: true,
      default_role_register: "user",

      // JWT configuration
      jwt: {
        secret: process.env.JWT_SECRET!,
        alg: "HS256",
        expires: 604800,  // 7 days
        issuer: "my-app",
        fields: ["id", "email", "role"],
      },

      // Cookie configuration
      cookie: {
        secure: process.env.NODE_ENV === "production",
        httpOnly: true,
        sameSite: "lax",
        expires: 604800,
        renew: true,
        pathSuccess: "/dashboard",
        pathLoggedOut: "/login",
      },

      // Password strategy
      strategies: {
        password: {
          type: "password",
          enabled: true,
          config: {
            hashing: "bcrypt",
            rounds: 4,
            minLength: 8,
          },
        },
      },

      // Roles
      roles: {
        admin: {
          implicit_allow: true,
        },
        editor: {
          implicit_allow: false,
          permissions: [
            { permission: "data.posts.read", effect: "allow" },
            { permission: "data.posts.create", effect: "allow" },
            { permission: "data.posts.update", effect: "allow" },
            { permission: "data.posts.delete", effect: "allow" },
          ],
        },
        user: {
          implicit_allow: false,
          is_default: true,
          permissions: [
            { permission: "data.posts.read", effect: "allow" },
          ],
        },
      },
    },
  },
  options: {
    seed: async (ctx) => {
      // Create initial admin on first run
      const adminExists = await ctx.em.repo("users").findOne({
        where: { email: { $eq: "admin@example.com" } },
      });

      if (!adminExists) {
        await ctx.app.module.auth.createUser({
          email: "admin@example.com",
          password: process.env.ADMIN_PASSWORD || "changeme123",
          role: "admin",
        });
        console.log("Admin user created");
      }
    },
  },
};

serve(config);
遵循安全最佳实践的完整身份验证配置:
typescript
import { serve, type BunBkndConfig } from "bknd/adapter/bun";
import { em, entity, text, date } from "bknd";

const schema = em({
  users: entity("users", {
    email: text().required().unique(),
    name: text(),
    avatar: text(),
    created_at: date({ default_value: "now" }),
  }),
  posts: entity("posts", {
    title: text().required(),
    content: text(),
  }),
});

type Database = (typeof schema)["DB"];
declare module "bknd" {
  interface DB extends Database {}
}

const config: BunBkndConfig = {
  connection: { url: process.env.DB_URL || "file:data.db" },
  config: {
    data: schema.toJSON(),
    auth: {
      enabled: true,
      basepath: "/api/auth",
      entity_name: "users",
      allow_register: true,
      default_role_register: "user",

      // JWT配置
      jwt: {
        secret: process.env.JWT_SECRET!,
        alg: "HS256",
        expires: 604800,  // 7天
        issuer: "my-app",
        fields: ["id", "email", "role"],
      },

      // Cookie配置
      cookie: {
        secure: process.env.NODE_ENV === "production",
        httpOnly: true,
        sameSite: "lax",
        expires: 604800,
        renew: true,
        pathSuccess: "/dashboard",
        pathLoggedOut: "/login",
      },

      // 密码策略
      strategies: {
        password: {
          type: "password",
          enabled: true,
          config: {
            hashing: "bcrypt",
            rounds: 4,
            minLength: 8,
          },
        },
      },

      // 角色配置
      roles: {
        admin: {
          implicit_allow: true,
        },
        editor: {
          implicit_allow: false,
          permissions: [
            { permission: "data.posts.read", effect: "allow" },
            { permission: "data.posts.create", effect: "allow" },
            { permission: "data.posts.update", effect: "allow" },
            { permission: "data.posts.delete", effect: "allow" },
          ],
        },
        user: {
          implicit_allow: false,
          is_default: true,
          permissions: [
            { permission: "data.posts.read", effect: "allow" },
          ],
        },
      },
    },
  },
  options: {
    seed: async (ctx) => {
      // 首次运行时创建初始管理员
      const adminExists = await ctx.em.repo("users").findOne({
        where: { email: { $eq: "admin@example.com" } },
      });

      if (!adminExists) {
        await ctx.app.module.auth.createUser({
          email: "admin@example.com",
          password: process.env.ADMIN_PASSWORD || "changeme123",
          role: "admin",
        });
        console.log("Admin user created");
      }
    },
  },
};

serve(config);

Auth Endpoints

身份验证端点

After setup, these endpoints are available:
MethodPathDescription
POST
/api/auth/password/login
Login with email/password
POST
/api/auth/password/register
Register new user
GET
/api/auth/me
Get current user
POST
/api/auth/logout
Log out (clear cookie)
GET
/api/auth/strategies
List enabled strategies
配置完成后,将启用以下端点:
请求方法路径说明
POST
/api/auth/password/login
使用邮箱/密码登录
POST
/api/auth/password/register
注册新用户
GET
/api/auth/me
获取当前用户信息
POST
/api/auth/logout
登出(清除Cookie)
GET
/api/auth/strategies
查看已启用的验证策略

Environment Variables

环境变量

Recommended env vars for auth:
bash
undefined
推荐用于身份验证的环境变量:
bash
undefined

.env

.env

JWT_SECRET=your-256-bit-secret-minimum-32-characters-long ADMIN_PASSWORD=secure-initial-admin-password

Generate a secure secret:

```bash
JWT_SECRET=your-256-bit-secret-minimum-32-characters-long ADMIN_PASSWORD=secure-initial-admin-password

生成安全密钥的命令:

```bash

Generate 64-character random string

生成64位随机字符串

openssl rand -hex 32
undefined
openssl rand -hex 32
undefined

Development vs Production

开发环境 vs 生产环境

SettingDevelopmentProduction
jwt.secret
Can use placeholderRequired, strong secret
cookie.secure
false
true
(HTTPS only)
strategies.password.config.hashing
sha256
bcrypt
allow_register
true
Consider
false
for closed systems
Dev config shortcut:
typescript
const isDev = process.env.NODE_ENV !== "production";

{
  auth: {
    enabled: true,
    jwt: {
      secret: isDev ? "dev-secret-not-for-production" : process.env.JWT_SECRET!,
      expires: isDev ? 86400 * 30 : 604800,  // 30 days dev, 7 days prod
    },
    cookie: {
      secure: !isDev,
    },
    strategies: {
      password: {
        type: "password",
        config: {
          hashing: isDev ? "sha256" : "bcrypt",
        },
      },
    },
  },
}
设置项开发环境生产环境
jwt.secret
可使用占位符必填,需使用高强度密钥
cookie.secure
false
true
(仅HTTPS环境)
strategies.password.config.hashing
sha256
bcrypt
allow_register
true
若为封闭系统,建议设为
false
开发环境配置快捷方式:
typescript
const isDev = process.env.NODE_ENV !== "production";

{
  auth: {
    enabled: true,
    jwt: {
      secret: isDev ? "dev-secret-not-for-production" : process.env.JWT_SECRET!,
      expires: isDev ? 86400 * 30 : 604800,  // 开发环境30天,生产环境7天
    },
    cookie: {
      secure: !isDev,
    },
    strategies: {
      password: {
        type: "password",
        config: {
          hashing: isDev ? "sha256" : "bcrypt",
        },
      },
    },
  },
}

Common Pitfalls

常见问题

Missing JWT Secret in Production

生产环境缺失JWT密钥

Problem:
Cannot sign JWT without secret
error
Fix: Set JWT secret via environment variable:
typescript
{
  auth: {
    jwt: {
      secret: process.env.JWT_SECRET,  // Never hardcode in production
    },
  },
}
问题: 出现
Cannot sign JWT without secret
错误
解决方法: 通过环境变量设置JWT密钥:
typescript
{
  auth: {
    jwt: {
      secret: process.env.JWT_SECRET,  // 生产环境绝对禁止硬编码
    },
  },
}

Cookie Not Set (HTTPS Issues)

Cookie未成功设置(HTTPS问题)

Problem: Auth cookie not set in browser
Fix: Set
secure: false
for local development:
typescript
{
  auth: {
    cookie: {
      secure: process.env.NODE_ENV === "production",  // false for localhost
    },
  },
}
问题: 浏览器中未设置身份验证Cookie
解决方法: 本地开发时将
secure
设为
false
typescript
{
  auth: {
    cookie: {
      secure: process.env.NODE_ENV === "production",  // 本地环境设为false
    },
  },
}

Role Not Found

角色未找到

Problem:
Role "admin" not found
when creating users
Fix: Define roles before referencing them:
typescript
{
  auth: {
    roles: {
      admin: { implicit_allow: true },  // Define first
      user: { implicit_allow: false },
    },
    default_role_register: "user",  // Now can reference
  },
}
问题: 创建用户时出现
Role "admin" not found
错误
解决方法: 先定义角色再引用:
typescript
{
  auth: {
    roles: {
      admin: { implicit_allow: true },  // 先定义角色
      user: { implicit_allow: false },
    },
    default_role_register: "user",  // 再进行引用
  },
}

Registration Disabled

注册功能被禁用

Problem:
Registration not allowed
error
Fix: Enable registration:
typescript
{
  auth: {
    allow_register: true,  // Default is true, but check if explicitly disabled
  },
}
问题: 出现
Registration not allowed
错误
解决方法: 启用注册功能:
typescript
{
  auth: {
    allow_register: true,  // 默认值为true,但需检查是否被显式禁用
  },
}

Weak Password Hashing

密码哈希强度不足

Problem: Using
plain
or
sha256
in production
Fix: Use bcrypt for production:
typescript
{
  auth: {
    strategies: {
      password: {
        config: {
          hashing: "bcrypt",
          rounds: 4,  // Balance security and performance
        },
      },
    },
  },
}
问题: 生产环境中使用
plain
sha256
哈希算法
解决方法: 生产环境使用bcrypt:
typescript
{
  auth: {
    strategies: {
      password: {
        config: {
          hashing: "bcrypt",
          rounds: 4,  // 平衡安全性与性能
        },
      },
    },
  },
}

Verification

验证方法

After setup, verify auth works:
1. Check enabled strategies:
bash
curl http://localhost:7654/api/auth/strategies
2. Register a test user:
bash
curl -X POST http://localhost:7654/api/auth/password/register \
  -H "Content-Type: application/json" \
  -d '{"email": "test@example.com", "password": "password123"}'
3. Login:
bash
curl -X POST http://localhost:7654/api/auth/password/login \
  -H "Content-Type: application/json" \
  -d '{"email": "test@example.com", "password": "password123"}'
4. Check current user (with token):
bash
curl http://localhost:7654/api/auth/me \
  -H "Authorization: Bearer <token-from-login>"
配置完成后,验证身份验证功能是否正常:
1. 检查已启用的策略:
bash
curl http://localhost:7654/api/auth/strategies
2. 注册测试用户:
bash
curl -X POST http://localhost:7654/api/auth/password/register \
  -H "Content-Type: application/json" \
  -d '{"email": "test@example.com", "password": "password123"}'
3. 登录:
bash
curl -X POST http://localhost:7654/api/auth/password/login \
  -H "Content-Type: application/json" \
  -d '{"email": "test@example.com", "password": "password123"}'
4. 查看当前用户信息(需携带令牌):
bash
curl http://localhost:7654/api/auth/me \
  -H "Authorization: Bearer <token-from-login>"

Security Checklist

安全检查清单

Before deploying to production:
  • Set strong
    jwt.secret
    (256-bit minimum)
  • Use
    hashing: "bcrypt"
    for password strategy
  • Set
    cookie.secure: true
    (HTTPS only)
  • Set
    cookie.httpOnly: true
    (default)
  • Set
    cookie.sameSite: "lax"
    or
    "strict"
  • Configure
    jwt.expires
    (don't leave unlimited)
  • Review
    allow_register
    setting
  • Create admin user via seed (not via public registration)
  • Store secrets in environment variables
部署到生产环境前需完成以下检查:
  • 设置高强度
    jwt.secret
    (至少256位)
  • 密码策略使用
    hashing: "bcrypt"
  • 设置
    cookie.secure: true
    (仅HTTPS环境)
  • 确保
    cookie.httpOnly: true
    (默认值)
  • 设置
    cookie.sameSite: "lax"
    "strict"
  • 配置
    jwt.expires
    (禁止设置为永不过期)
  • 检查
    allow_register
    设置
  • 通过种子脚本创建管理员用户(而非公开注册)
  • 将密钥存储在环境变量中

DOs and DON'Ts

注意事项

DO:
  • Use environment variables for secrets
  • Use bcrypt hashing in production
  • Set JWT expiry times
  • Define roles before assigning them
  • Test auth flow after configuration changes
DON'T:
  • Hardcode JWT secrets in code
  • Use
    plain
    hashing in production
  • Skip setting
    cookie.secure
    in production
  • Leave registration open if not needed
  • Forget to create initial admin user
建议:
  • 使用环境变量存储密钥
  • 生产环境使用bcrypt哈希算法
  • 设置JWT过期时间
  • 先定义角色再进行分配
  • 配置变更后测试身份验证流程
禁止:
  • 在代码中硬编码JWT密钥
  • 生产环境使用
    plain
    哈希算法
  • 生产环境跳过
    cookie.secure
    设置
  • 不需要公开注册时仍保持开启状态
  • 忘记创建初始管理员用户

Related Skills

相关技能

  • bknd-create-user - Create user accounts programmatically
  • bknd-login-flow - Implement login/logout functionality
  • bknd-registration - Set up user registration flows
  • bknd-oauth-setup - Configure OAuth providers (Google, GitHub)
  • bknd-create-role - Define roles for authorization
  • bknd-session-handling - Manage user sessions
  • bknd-create-user - 以编程方式创建用户账号
  • bknd-login-flow - 实现登录/登出功能
  • bknd-registration - 设置用户注册流程
  • bknd-oauth-setup - 配置OAuth服务商(Google、GitHub等)
  • bknd-create-role - 定义用于授权的角色
  • bknd-session-handling - 管理用户会话