参考

API 密钥插件选项、权限及模式参考。

API 密钥插件选项

configId string

该配置的唯一标识符。在使用多个配置时必填。默认值为 "default"

references "user" | "organization"

API 密钥所关联的主体。此设置决定了 API 密钥的拥有权。默认值为 "user"

  • "user":API 密钥归用户所有(创建时需提供 userId
  • "organization":API 密钥归组织所有(创建时需提供 organizationId

apiKeyHeaders string | string[];

用于检测 API 密钥的请求头名称。默认值为 x-api-key

customAPIKeyGetter (ctx: GenericEndpointContext) => string | null

自定义函数,从上下文中获取 API 密钥。

customAPIKeyValidator (options: { ctx: GenericEndpointContext; key: string; }) => boolean | Promise<boolean>

自定义函数,用于验证 API 密钥。

customKeyGenerator (options: { length: number; prefix: string | undefined; }) => string | Promise<string>

自定义函数,用于生成 API 密钥。

startingCharactersConfig { shouldStore?: boolean; charactersLength?: number; }

自定义起始字符配置。

defaultKeyLength number

API 密钥的长度,越长越好。默认值为 64。(不包括前缀长度)

defaultPrefix string

API 密钥的前缀。

注意:建议给前缀添加下划线以便更好识别,如 hello_

maximumPrefixLength number

前缀的最大长度。

minimumPrefixLength number

前缀的最小长度。

requireName boolean

是否要求必须填写 API 密钥名称。默认值为 false

maximumNameLength number

名称的最大长度。

minimumNameLength number

名称的最小长度。

enableMetadata boolean

是否启用 API 密钥的元数据。

keyExpiration { defaultExpiresIn?: number | null; disableCustomExpiresTime?: boolean; minExpiresIn?: number; maxExpiresIn?: number; }

自定义密钥过期时间。

rateLimit { enabled?: boolean; timeWindow?: number; maxRequests?: number; }

自定义速率限制。

schema InferOptionSchema<ReturnType<typeof apiKeySchema>>

API 密钥插件的自定义模式。

enableSessionForAPIKeys boolean

API 密钥可以代表一个有效会话,因此如果在请求头中找到有效的 API 密钥,可以模拟用户会话。默认值为 false

storage "database" | "secondary-storage"

API 密钥的存储后端。默认值为 "database"

  • "database":存储于数据库适配器(默认)
  • "secondary-storage":存储于配置的二级存储(例如 Redis)

fallbackToDatabase boolean

storage 设为 "secondary-storage" 时,若未在二级存储中找到密钥,是否回退至数据库查找。 默认值为 false

storage 设置为 "secondary-storage" 时,必须在 Better Auth 配置中指定 secondaryStorage。API 密钥将使用如下键值模式存储:

  • api-key:${hashedKey} - 通过哈希密钥的主查找键
  • api-key:by-id:${id} - 通过 ID 查找
  • api-key:by-ref:${referenceId} - 关联的 API 密钥列表(用户或组织)

若 API 密钥设置了过期时间(expiresAt),二级存储会自动设置 TTL 以实现自动清理。

auth.ts
import { betterAuth } from "better-auth";
import { apiKey } from "better-auth/plugins"

export const auth = betterAuth({
  secondaryStorage: {
    get: async (key) => {
      return await redis.get(key);
    },
    set: async (key, value, ttl) => {
      if (ttl) await redis.set(key, value, { EX: ttl });
      else await redis.set(key, value);
    },
    delete: async (key) => {
      await redis.del(key);
    },
  },
  plugins: [
    apiKey({
      storage: "secondary-storage",
    }),
  ],
});

customStorage { get: (key: string) => Promise<unknown> | unknown; set: (key: string, value: string, ttl?: number) => Promise<void | null | unknown> | void; delete: (key: string) => Promise<void | null | string> | void; }

API 密钥的自定义存储方法。如果提供,该方法会优先于 ctx.context.secondaryStorage 使用。

适用于想为 API 密钥使用不同于全局二级存储的存储后端,或者需要自定义存储逻辑的场景。

auth.ts
import { betterAuth } from "better-auth";
import { apiKey } from "better-auth/plugins"

export const auth = betterAuth({
  plugins: [
    apiKey({
      storage: "secondary-storage",
      customStorage: {
        get: async (key) => await customStorage.get(key),
        set: async (key, value, ttl) => await customStorage.set(key, value, ttl),
        delete: async (key) => await customStorage.delete(key), 
      },
    }),
  ],
});

deferUpdates boolean

将非关键的更新(如速率限制计数器、时间戳、剩余请求数)推迟到响应发送后,通过全局的 backgroundTasks 处理器异步执行。此设置在无服务器架构中显著提升响应速度。默认值为 false

需要在主认证配置中设置 backgroundTasks.handler

启用该选项会引入最终一致性,即响应先返回乐观数据,数据库更新稍后完成。只在应用能容忍该延迟情况下启用,以提升性能。

import { waitUntil } from "@vercel/functions";

export const auth = betterAuth({
  advanced: { 
      backgroundTasks: {
         handler: waitUntil,
      },
  }
  plugins: [
    apiKey({
      deferUpdates: true,
    }),
  ],
});
import { AsyncLocalStorage } from "node:async_hooks";

const execCtxStorage = new AsyncLocalStorage<ExecutionContext>();

export const auth = betterAuth({
  advanced: { 
      backgroundTasks: {
         handler: waitUntil,
      },
  }
  plugins: [
    apiKey({
      deferUpdates: true,
    }),
  ],
});

// 在请求处理器中,使用 execCtxStorage.run(ctx, ...) 包裹

permissions { defaultPermissions?: Statements | ((referenceId: string, ctx: GenericEndpointContext) => Statements | Promise<Statements>) }

API 密钥的权限设置。

关于权限的详细说明请参见下文 权限

disableKeyHashing boolean

是否禁用 API 密钥的哈希存储。

安全警告:强烈建议不要禁用哈希存储。 明文存储 API 密钥可能在数据库泄露时导致所有用户的密钥暴露。


权限

API 密钥可以绑定权限,用以实现细粒度的访问控制。权限结构为资源类型与允许操作数组的映射。

设置默认权限

可以配置默认权限,应用于所有新创建的 API 密钥:

auth.ts
import { betterAuth } from "better-auth"
import { apiKey } from "better-auth/plugins"

export const auth = betterAuth({
  plugins: [
    apiKey({
      permissions: {
        defaultPermissions: {
          files: ["read"],
          users: ["read"],
        },
      },
    }),
  ],
});

也可以提供一个函数动态返回权限:

auth.ts
import { betterAuth } from "better-auth"
import { apiKey } from "better-auth/plugins"

export const auth = betterAuth({
  plugins: [
    apiKey({
      permissions: {
        defaultPermissions: async (referenceId, ctx) => {
          // referenceId 是 userId 或 orgId,取决于配置
          // 根据用户/组织角色或其他数据决定权限
          return {
            files: ["read"],
            users: ["read"],
          };
        },
      },
    }),
  ],
});

创建带有权限的 API 密钥

创建 API 密钥时可以指定自定义权限:

create-api-key.ts
import { auth } from "@/lib/auth"

const apiKey = await auth.api.createApiKey({
  body: {
    name: "My API Key",
    permissions: {
      files: ["read", "write"],
      users: ["read"],
    },
    userId: "userId",
  },
});

验证带权限的 API 密钥

验证 API 密钥时,可以检测是否具备所需权限:

verify-api-key.ts
import { auth } from "@/lib/auth"

const result = await auth.api.verifyApiKey({
  body: {
    key: "your_api_key_here",
    permissions: {
      files: ["read"],
    },
  },
});

if (result.valid) {
  // API 密钥有效且拥有所需权限
} else {
  // API 密钥无效或权限不足
}

更新 API 密钥权限

可以修改已有 API 密钥的权限:

update-api-key.ts
import { auth } from "@/lib/auth"

const apiKey = await auth.api.updateApiKey({
  body: {
    keyId: existingApiKeyId,
    permissions: {
      files: ["read", "write", "delete"],
      users: ["read", "write"],
    },
  },
  headers: user_headers,
});

权限结构

权限采用基于资源的结构:

type Permissions = {
  [resourceType: string]: string[];
};

// 示例:
const permissions = {
  files: ["read", "write", "delete"],
  users: ["read"],
  projects: ["read", "write"],
};

验证时,API 密钥必须包含所有请求的所需权限,才能校验通过。

模式

表:apikey

Table
字段
类型
描述
id
string
pk
API 密钥的 ID。
configId
string
此密钥所属的配置 ID。默认值为 'default'。
name
string
?
API 密钥名称。
start
string
?
API 密钥的起始字符,方便在界面展示前几位用于识别。
prefix
string
?
API 密钥前缀,存为明文。
key
string
API 密钥哈希值。
referenceId
string
拥有者 ID(依据配置的 `references` 设置,是用户或组织 ID)。
refillInterval
number
?
密钥剩余额度的补充间隔,单位毫秒。
refillAmount
number
?
补充到剩余额度的数量。
lastRefillAt
Date
?
上次补充额度的时间。
enabled
boolean
API 密钥是否启用。
rateLimitEnabled
boolean
是否启用速率限制。
rateLimitTimeWindow
number
?
速率限制的时间窗口,单位毫秒。
rateLimitMax
number
?
时间窗口内允许的最大请求数。
requestCount
number
当前时间窗口内已发起的请求数。
remaining
number
?
剩余的请求次数。
lastRequest
Date
?
最后一次请求时间。
expiresAt
Date
?
密钥过期时间。
createdAt
Date
API 密钥创建时间。
updatedAt
Date
API 密钥更新时间。
permissions
string
?
密钥权限。
metadata
Object
?
任意附加元数据。

从旧版本迁移

从旧版本升级时,需要将 userId 字段迁移至新的 referenceId 系统:

-- 添加新列
ALTER TABLE apikey ADD COLUMN config_id VARCHAR(255) NOT NULL DEFAULT 'default';
ALTER TABLE apikey ADD COLUMN reference_id VARCHAR(255);

-- 迁移现有数据(把 userId 拷贝到 referenceId)
UPDATE apikey SET reference_id = user_id WHERE reference_id IS NULL;

-- 将 reference_id 设为非空并创建索引
ALTER TABLE apikey ALTER COLUMN reference_id SET NOT NULL;
CREATE INDEX idx_apikey_reference_id ON apikey(reference_id);
CREATE INDEX idx_apikey_config_id ON apikey(config_id);

-- 迁移确认无误后,可选择删除旧列
-- ALTER TABLE apikey DROP COLUMN user_id;

重大变更userId 字段已被替换为 referenceId。API 响应中返回 referenceId 而非 userId。拥有者类型(用户或组织)由配置的 references 决定,不会存储在每个密钥上。