参考

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

API 密钥插件选项

configId string

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

references "user" | "organization"

What the API key references. This determines ownership over the API key. Default is "user".

  • "user": API keys are owned by users (requires userId on creation)
  • "organization": API keys are owned by organizations (requires organizationId on creation)

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": Store API keys in the database adapter (default)
  • "secondary-storage": Store API keys in the configured secondary storage (e.g., Redis)

fallbackToDatabase boolean

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

When storage is set to "secondary-storage", you must configure secondaryStorage in your Better Auth options. API keys will be stored using key-value patterns:

  • api-key:${hashedKey} - Primary lookup by hashed key
  • api-key:by-id:${id} - Lookup by ID
  • api-key:by-ref:${referenceId} - Reference's API key list (user or organization)

If an API key has an expiration date (expiresAt), a TTL will be automatically set in secondary storage to ensure automatic cleanup.

auth.ts
import { betterAuth } from "better-auth";
import { apiKey } from "@better-auth/api-key"

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/api-key"

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 密钥的哈希存储。

Security Warning: It's strongly recommended to not disable hashing. Storing API keys in plaintext makes them vulnerable to database breaches, potentially exposing all your users' API keys.


权限

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

设置默认权限

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

auth.ts
import { betterAuth } from "better-auth"
import { apiKey } from "@better-auth/api-key"

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

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

auth.ts
import { betterAuth } from "better-auth"
import { apiKey } from "@better-auth/api-key"

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
The ID of the API key.
configId
string
-
The configuration ID this key belongs to. Default is 'default'.
name ?
string
-
The name of the API key.
start ?
string
-
The starting characters of the API key. Useful for showing the first few characters of the API key in the UI for the users to easily identify.
prefix ?
string
-
The API Key prefix. Stored as plain text.
key
string
-
The hashed API key itself.
referenceId
string
-
The ID of the owner (user ID or organization ID based on the config's `references` setting).
refillInterval ?
number
-
The interval to refill the key in milliseconds.
refillAmount ?
number
-
The amount to refill the remaining count of the key.
lastRefillAt ?
Date
-
The date and time when the key was last refilled.
enabled ?
boolean
-
Whether the API key is enabled.
rateLimitEnabled ?
boolean
-
Whether the API key has rate limiting enabled.
rateLimitTimeWindow ?
number
-
The time window in milliseconds for the rate limit.
rateLimitMax ?
number
-
The maximum number of requests allowed within the `rateLimitTimeWindow`.
requestCount ?
number
-
The number of requests made within the rate limit time window.
remaining ?
number
-
The number of requests remaining.
lastRequest ?
Date
-
The date and time of the last request made to the key.
expiresAt ?
Date
-
The date and time when the key will expire.
createdAt
Date
-
The date and time the API key was created.
updatedAt
Date
-
The date and time the API key was updated.
permissions ?
string
-
The permissions of the key.
metadata ?
string
-
Any additional metadata you want to store with the key.

从旧版本迁移

从旧版本升级时,需要将 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 决定,不会存储在每个密钥上。