API Key
API Key plugin for Better Auth.
The API Key plugin allows you to create and manage API keys for your application. It provides a way to authenticate and authorize API requests by verifying API keys.
Features
- Create, manage, and verify API keys
- Built-in rate limiting
- Custom expiration times, remaining count, and refill systems
- Metadata for API keys
- Custom prefix
- Sessions from API keys
- Secondary storage support for high-performance API key lookups
- Multiple configurations for different API key types
- Organization-owned API keys in addition to user-owned keys
Installation
Install the plugin
npm install @better-auth/api-keyAdd Plugin to the server
import { betterAuth } from "better-auth"
import { apiKey } from "@better-auth/api-key"
export const auth = betterAuth({
plugins: [
apiKey()
]
})Migrate the database
Run the migration or generate the schema to add the necessary fields and tables to the database.
npx auth migratenpx auth generateSee the Schema section to add the fields manually.
Add the client plugin
import { createAuthClient } from "better-auth/client"
import { apiKeyClient } from "@better-auth/api-key/client"
export const authClient = createAuthClient({
plugins: [
apiKeyClient()
]
})Usage
You can view the list of API Key plugin options here.
Create an API key
You can adjust more specific API key configurations by using the server method instead.
const { data, error } = await authClient.apiKey.create({ configId, name: 'project-api-key', expiresIn: 60 * 60 * 24 * 7, organizationId: "org-id", prefix: 'project-api-key', metadata: { someKey: 'someValue' },});configIdstringThe configuration ID to use. If not provided, the default configuration is used.
namestringName of the Api Key.
expiresInnumberExpiration time of the Api Key in seconds.
organizationIdstringOrganization Id that the Api Key belongs to. Required for organization-owned keys (when config has references: "organization").
prefixstringPrefix of the Api Key.
metadataany | nullMetadata of the Api Key.
references setting.Result
It'll return the ApiKey object which includes the key value for you to use.
Otherwise if it throws, it will throw an APIError.
Verify an API key
const permissions = { // Permissions to check are optional. projects: ["read", "read-write"],}const data = await auth.api.verifyApiKey({ body: { configId, key: "your_api_key_here", // required permissions, },});configIdstringThe configuration ID to use for verification. If not provided, the default configuration is used.
keystringrequiredThe key to verify.
permissionsRecord<string, string[]>The permissions to verify. Optional.
Result
type Result = {
valid: boolean;
error: { message: string; code: string } | null;
key: Omit<ApiKey, "key"> | null;
};Get an API key
const { data, error } = await authClient.apiKey.get({ query: { configId, id: "some-api-key-id", // required },});configIdstringThe configuration ID to use for the API key lookup. If not provided, the default configuration is used.
idstringrequiredThe id of the Api Key.
Result
You'll receive everything about the API key details, except for the key value itself.
If it fails, it will throw an APIError.
type Result = Omit<ApiKey, "key">;Update an API key
const { data, error } = await authClient.apiKey.update({ configId, keyId: "some-api-key-id", // required name: "some-api-key-name",});configIdstringThe configuration ID to use for the API key lookup. If not provided, the default configuration is used.
keyIdstringrequiredThe id of the Api Key to update.
namestringThe name of the key.
Result
If fails, throws APIError.
Otherwise, you'll receive the API Key details, except for the key value itself.
Delete an API Key
This endpoint is attempting to delete the API key from the perspective of the user. It will check if the user's ID matches the key owner to be able to delete it. If you want to delete a key without these checks, we recommend you use an ORM to directly mutate your DB instead.
const { data, error } = await authClient.apiKey.delete({ configId, keyId: "some-api-key-id", // required});configIdstringThe configuration ID to use for the API key lookup. If not provided, the default configuration is used.
keyIdstringrequiredThe id of the Api Key to delete.
Result
If fails, throws APIError.
Otherwise, you'll receive:
type Result = {
success: boolean;
};List API keys
const { data, error } = await authClient.apiKey.list({ query: { configId, organizationId, limit, offset, sortBy, sortDirection, },});configIdstringFilter by configuration ID. If not provided, returns keys from all configurations.
organizationIdstringOrganization ID to list keys for. If provided, returns organization-owned keys. If not provided, returns user-owned keys for the current session user.
limitnumberThe number of API keys to return.
offsetnumberThe offset to start from (for pagination).
sortBystringThe field to sort by (e.g., "createdAt", "name", "expiresAt").
sortDirection"asc" | "desc"The direction to sort by.
Result
If fails, throws APIError.
Otherwise, you'll receive a paginated response:
type Result = {
apiKeys: Omit<ApiKey, "key">[];
total: number;
limit?: number;
offset?: number;
};Pagination Examples
// Get first 10 API keys for the current user
const result = await authClient.apiKey.list({
query: { limit: 10 }
});
// Get second page (10 items per page)
const page2 = await authClient.apiKey.list({
query: { limit: 10, offset: 10 }
});
// Sort by creation date (newest first)
const sorted = await authClient.apiKey.list({
query: { sortBy: "createdAt", sortDirection: "desc" }
});
// Combined pagination and sorting
const combined = await authClient.apiKey.list({
query: {
limit: 20,
offset: 0,
sortBy: "name",
sortDirection: "asc"
}
});
// List organization-owned keys
const orgKeys = await authClient.apiKey.list({
query: { organizationId: "org_123" }
});
// List organization keys with specific config
const orgPublicKeys = await authClient.apiKey.list({
query: {
organizationId: "org_123",
configId: "public"
}
});Delete all expired API keys
This function will delete all API keys that have an expired expiration date.
const data = await auth.api.deleteAllExpiredApiKeys();We automatically delete expired API keys every time any apiKey plugin endpoints were called, however they are rate-limited to a 10 second cool down each call to prevent multiple calls to the database.