Skip to content

[feature] Self-host: an API key should not be able to mint or revoke API keys #2157

Description

@ramarivera

The problem

On self-host, an API key can mint more API keys.

The apiKey plugin runs with enableSessionForAPIKeys (better-auth.ts, L170). Its before-hook turns any request that carries a valid x-api-key header into its owner's session, on every Better Auth endpoint. /api/auth/* goes straight to Better Auth (app.ts), and the account provider hands the raw request headers to Better Auth (getSession better-auth-account-provider.ts, createApiKey L89-L91).

Reading the code, a request with a key in x-api-key to POST /api/account/api-keys (or POST /api/auth/api-key/create) gets a session and creates a new key for the same user. Listing and revoking keys work the same way. I traced this through the source on current main and @better-auth/api-key 1.6.x; I haven't reproduced it against a running instance.

The result: once a key leaks, revoking that key doesn't contain the leak, because the holder may already have minted others. The only safe response is to revoke every key on the account.

Cloud already draws this line. /account/* accepts only the browser session cookie, "NOT api-key Bearer" (account-api.ts). #2077 applies the same rule to its new /api/access/* routes and refuses any request carrying Authorization or x-api-key.

Proposed shape

On self-host, refuse key management when the caller authenticated with an API key (the x-api-key header, or a Bearer value that resolves only as an API key):

  • /api/account/api-keys list, create and revoke;
  • Better Auth's own /api/auth/api-key/* endpoints.

It's worth checking the other account-changing Better Auth endpoints too (password and profile changes, organization invites), since the same key-derived session reaches them.

Why it matters for security

An API key should be able to do what its owner allowed, and not make itself harder to revoke. Keys are handed to agent runtimes precisely because those runtimes are the likeliest place for a credential to leak.

Alternatives

Operators can watch the key list and revoke anything they didn't create, but that's detection after the fact, and it only works if nothing else creates keys on the account.

Where it belongs

Self-host (Docker)

Before you submit

  • I searched the open issues for a duplicate.

Activity

  1. RhysSullivan commented on Oct 8, 2026

    @RhysSullivan
    Collaborator

    We're clearing the backlog ahead of the v2 launch, so we're closing this. If it still applies to v2, please open a new issue or PR against v2.

    Sent from my Claude

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions