API Key
Add programmatic API key management with create, copy, and revoke flows to your authentication settings.
The API key plugin adds programmatic API key management to your authentication UI. Users can create, copy, and revoke API keys from a security card in account settings. New keys can use a configurable expiration interval, and each listed key shows when it expires.
It contributes:
- An
<ApiKeys />card to the security settings tab for user-owned keys - An
<OrganizationApiKeys />card to<OrganizationSettings />for organization-owned keys (opt-in viaapiKeyPlugin({ organization: true }); requires the organization plugin and a matching server-side API key config)
Setup
Install the Better Auth plugin
Install the @better-auth/api-key package and add it to your Better Auth server config:
import { betterAuth } from "better-auth"
import { apiKey } from "@better-auth/api-key"
export const auth = betterAuth({
// ...
plugins: [
apiKey()
]
})Install the matching client plugin
Add apiKeyClient() to your auth client so authClient.apiKey.* methods are available:
import { createAuthClient } from "better-auth/react"
import { apiKeyClient } from "@better-auth/api-key/client"
export const authClient = createAuthClient({
plugins: [apiKeyClient()]
})Install the UI plugin
Run the shadcn CLI to install the API key components and the apiKeyPlugin() factory into your project:
npx shadcn@latest registry add @better-auth-ui=https://better-auth-ui.com/r/{style}/{name}.jsonnpx shadcn@latest add @better-auth-ui/api-keyThis drops the following into your codebase:
src/lib/auth/auth-plugin.ts— localAuthPlugintyping widenersrc/lib/auth/api-key-plugin.ts—apiKeyPlugin()factorysrc/components/auth/api-key/api-keys.tsx— the API keys security cardsrc/components/auth/api-key/api-key.tsx— individual API key row with delete controlsrc/components/auth/api-key/api-keys-empty.tsx— empty state shown when no keys existsrc/components/auth/api-key/api-key-skeleton.tsx— skeleton shown while keys are loadingsrc/components/auth/api-key/create-api-key-dialog.tsx— dialog for creating a new keysrc/components/auth/api-key/new-api-key-dialog.tsx— dialog showing the newly created key with copy buttonsrc/components/auth/api-key/delete-api-key-dialog.tsx— confirmation dialog for revoking a keysrc/components/auth/api-key/organization-api-keys.tsx— owner-gated wrapper that renders<ApiKeys />scoped to the active organization
Register the UI plugin
Pass apiKeyPlugin() to <AuthProvider>:
import { AuthProvider } from "@/components/auth/auth-provider"
import { apiKeyPlugin } from "@/lib/auth/api-key-plugin"
import { authClient } from "@/lib/auth-client"
<AuthProvider
authClient={authClient}
plugins={[
apiKeyPlugin()
]}
>
{children}
</AuthProvider>Configure expiration
The create dialog offers 30 days, 90 days, and Never by default. It initially selects 30 days. Configure the choices through apiKeyPlugin():
apiKeyPlugin({
keyExpiration: {
intervals: [7, 30, 90],
defaultInterval: 30,
allowNever: true
}
})intervals and defaultInterval use days. Better Auth receives the selected lifetime as seconds.
Keep the UI choices within the limits in your Better Auth server configuration:
apiKey({
keyExpiration: {
minExpiresIn: 7,
maxExpiresIn: 90,
defaultExpiresIn: null
}
})When allowNever is enabled, selecting Never sends no custom interval. Better Auth will still apply defaultExpiresIn if the server defines one, so set allowNever: false in the UI when your server always requires expiration.
To remove the expiration field and rely entirely on the server default:
apiKeyPlugin({ keyExpiration: false })Components
<ApiKeys />
API keys
The <ApiKeys /> security card is rendered on the security settings page when your layout renders each plugin's securityCards (as the example SecuritySettings does) and apiKeyPlugin() is in plugins.
Usage
import { ApiKeys } from "@/components/auth/api-key/api-keys"
<ApiKeys />Props
Prop
Type
<OrganizationApiKeys />
A thin wrapper around <ApiKeys /> that resolves the active organization via useActiveOrganization and forwards its id. Rendered inside <OrganizationSettings /> only when the plugin is registered with { organization: true }.
To enable, opt in on the UI plugin and add a matching API key configuration to your Better Auth server config. The plugin uses a fixed configId of "organization", so the server entry must be { configId: "organization", references: "organization" }:
import { AuthProvider } from "@/components/auth/auth-provider"
import { apiKeyPlugin } from "@/lib/auth/api-key-plugin"
import { authClient } from "@/lib/auth-client"
<AuthProvider
authClient={authClient}
plugins={[
apiKeyPlugin({ organization: true })
]}
>
{children}
</AuthProvider>import { betterAuth } from "better-auth"
import { apiKey } from "@better-auth/api-key"
import { organization } from "better-auth/plugins"
export const auth = betterAuth({
// ...
plugins: [
organization(),
apiKey([
{ configId: "default", references: "user" },
{ configId: "organization", references: "organization" }
])
]
})See the Better Auth docs for role-based permissions on organization-owned keys.
Usage
import { OrganizationApiKeys } from "@/components/auth/api-key/organization-api-keys"
<OrganizationApiKeys />Props
Prop
Type
Options
Prop
Type
Localization
Prop
Type
Last updated on