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

Installation

Install the plugin

npm install @better-auth/api-key

Add Plugin to the server

auth.ts
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 migrate
npx auth generate

See the Schema section to add the fields manually.

Add the client plugin

auth-client.ts
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

POST/api-key/create
Notes

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

The configuration ID to use. If not provided, the default configuration is used.

namestring

Name of the Api Key.

expiresInnumber

Expiration time of the Api Key in seconds.

organizationIdstring

Organization Id that the Api Key belongs to. Required for organization-owned keys (when config has references: "organization").

prefixstring

Prefix of the Api Key.

metadataany | null

Metadata of the Api Key.

API keys can be owned by either a user or an organization, depending on the configuration's 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,    },});
Parameters
configIdstring

The configuration ID to use for verification. If not provided, the default configuration is used.

keystringrequired

The 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

GET/api-key/get
const { data, error } = await authClient.apiKey.get({    query: {        configId,        id: "some-api-key-id", // required    },});
Parameters
configIdstring

The configuration ID to use for the API key lookup. If not provided, the default configuration is used.

idstringrequired

The 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

POST/api-key/update
const { data, error } = await authClient.apiKey.update({    configId,    keyId: "some-api-key-id", // required    name: "some-api-key-name",});
Parameters
configIdstring

The configuration ID to use for the API key lookup. If not provided, the default configuration is used.

keyIdstringrequired

The id of the Api Key to update.

namestring

The 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

POST/api-key/delete
Notes

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});
Parameters
configIdstring

The configuration ID to use for the API key lookup. If not provided, the default configuration is used.

keyIdstringrequired

The id of the Api Key to delete.

Result

If fails, throws APIError. Otherwise, you'll receive:

type Result = {
  success: boolean;
};

List API keys

GET/api-key/list
const { data, error } = await authClient.apiKey.list({    query: {        configId,        organizationId,        limit,        offset,        sortBy,        sortDirection,    },});
Parameters
configIdstring

Filter by configuration ID. If not provided, returns keys from all configurations.

organizationIdstring

Organization ID to list keys for. If provided, returns organization-owned keys. If not provided, returns user-owned keys for the current session user.

limitnumber

The number of API keys to return.

offsetnumber

The offset to start from (for pagination).

sortBystring

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

Next Steps