API Key Plugin: delete 404 #848

Closed
opened 2026-03-13 08:06:59 -05:00 by GiteaMirror · 10 comments
Owner

Originally created by @erickleinde on GitHub (Mar 14, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. create an API Key
  2. delete Api key

Current vs. Expected behavior

API key should be deleted, but the route is not found
POST /api/auth/api-key/delete 404 in 8ms

The route does not appear in the OpenAPI plugin either

Image

What version of Better Auth are you using?

1.2.4

Provide environment information

Tested on MacOS 15.3.1 and Windows 10 in Google Chrome. Node 22.14.0, NPM 11.2.0

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Additional context

No response

Originally created by @erickleinde on GitHub (Mar 14, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. create an API Key 2. delete Api key ### Current vs. Expected behavior API key should be deleted, but the route is not found `POST /api/auth/api-key/delete 404 in 8ms` The route does not appear in the OpenAPI plugin either <img width="269" alt="Image" src="https://github.com/user-attachments/assets/6cb15fc5-5aa6-4989-ad96-4c96c79bdd07" /> ### What version of Better Auth are you using? 1.2.4 ### Provide environment information ```bash Tested on MacOS 15.3.1 and Windows 10 in Google Chrome. Node 22.14.0, NPM 11.2.0 ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 08:06:59 -05:00
Author
Owner

@theabhayprajapati commented on GitHub (Mar 15, 2025):

@erickleinde
Thanks for reporting this issue! Looking at the code, I can see that the API key deletion endpoint is implemented using the DELETE method, but you're trying to call it with POST.

To fix this, please update your API call to use DELETE instead of POST:

Reference: https://github.com/better-auth/better-auth/blob/main/packages/better-auth/src/plugins/api-key/routes/delete-api-key.ts#L21

@theabhayprajapati commented on GitHub (Mar 15, 2025): @erickleinde Thanks for reporting this issue! Looking at the code, I can see that the API key deletion endpoint is implemented using the `DELETE` method, but you're trying to call it with `POST`. To fix this, please update your API call to use `DELETE` instead of `POST`: Reference: https://github.com/better-auth/better-auth/blob/main/packages/better-auth/src/plugins/api-key/routes/delete-api-key.ts#L21
Author
Owner

@florianmartens commented on GitHub (Mar 17, 2025):

Hey, this is actually an issue with the authClient plugin.

export const authClient = createAuthClient({
  baseURL: getServerUrl(),
  plugins: [apiKeyClient()],
});

const result = await authClient.apiKey.delete({ keyId: id });

Will issue a POST request instead of a DELETE request. This this is indeed a bug. It's also true that the route is missing from the reference which is another issue (I can confirm this).

@theabhayprajapati You're correct in stating that the docs point out a DELETE request is required for deletion:

Image

But the docs don't seem correct here.

It's unclear where the keyId goes. In the URL? DELETE requests don't have a body ... I tried the URL but kept getting 404s.

Maybe @Bekacru or @ping-maxwell have time to look at it.

I guess the only workaround for now is to add a new endpoint to your app and delete the API Key with SQL/ORM.

I'm on 1.2.4

I have two other small issues with this plugin:

Issue I: The naming of the postgres table apikeys is also somewhat against the convention of the other tables. It should be api_keys I guess.

Issue II: I'm unable to access the inferred type of the ApiKey from both the server and client SDKs. I would have expected type T = typeof authClient.$Infer.ApiKey to work.

@florianmartens commented on GitHub (Mar 17, 2025): Hey, this is actually an issue with the `authClient` plugin. ``` export const authClient = createAuthClient({ baseURL: getServerUrl(), plugins: [apiKeyClient()], }); const result = await authClient.apiKey.delete({ keyId: id }); ``` Will issue a `POST` request instead of a `DELETE` request. This this is indeed a bug. It's also true that the route is missing from the reference which is another issue (I can confirm this). @theabhayprajapati You're correct in stating that the docs point out a `DELETE` request is required for deletion: <img width="864" alt="Image" src="https://github.com/user-attachments/assets/d7e15c7a-07c5-4240-a55a-f08893995ffc" /> But the docs don't seem correct here. It's unclear where the `keyId` goes. In the URL? `DELETE` requests don't have a body ... I tried the URL but kept getting 404s. Maybe @Bekacru or @ping-maxwell have time to look at it. I guess the only workaround for now is to add a new endpoint to your app and delete the API Key with SQL/ORM. I'm on 1.2.4 I have two other small issues with this plugin: Issue I: The naming of the postgres table `apikeys` is also somewhat against the convention of the other tables. It should be `api_keys` I guess. Issue II: I'm unable to access the inferred type of the ApiKey from both the server and client SDKs. I would have expected `type T = typeof authClient.$Infer.ApiKey` to work.
Author
Owner

@ping-maxwell commented on GitHub (Mar 18, 2025):

I'll take a look

@ping-maxwell commented on GitHub (Mar 18, 2025): I'll take a look
Author
Owner

@ping-maxwell commented on GitHub (Mar 18, 2025):

Have you guys tested using auth.api.deleteApiKey?
Currently unit tests only test against the auth instance on deleting keys, not the auth-client. (I will fix this)
I also noticed that in the initial issue, the auth config doesn't include the apiKey plugin?

Change this:

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

to:

import { betterAuth } from "better-auth"
import { apiKey } from "better-auth/plugins"

export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
  plugins: [apiKey()],
});
@ping-maxwell commented on GitHub (Mar 18, 2025): Have you guys tested using `auth.api.deleteApiKey`? Currently unit tests only test against the auth instance on deleting keys, not the auth-client. (I will fix this) I also noticed that in the initial issue, the auth config doesn't include the apiKey plugin? Change this: ```ts import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` to: ```ts import { betterAuth } from "better-auth" import { apiKey } from "better-auth/plugins" export const auth = betterAuth({ emailAndPassword: { enabled: true }, plugins: [apiKey()], }); ```
Author
Owner

@florianmartens commented on GitHub (Mar 18, 2025):

I have not tried the server sdk for deleting API keys yet. By my config definitely contains the plugin.

export const auth = betterAuth({
  ...
  plugins: [
    openAPI(),
    organization({ organizationLimit: 1 }),
    apiKey({
      rateLimit: {
        enabled: true,
        timeWindow: 1000 * 60 * 60 * 24,
        maxRequests: 5_000,
      },
      apiKeyHeaders: ["x-api-key"],
      permissions: {
        defaultPermissions: () => {
          return {
            task: ["read", "write"],
          };
        },
      },
    }),
    admin(),
    sso(),
    bearer(),
  ],
  databaseHooks: {...},
});

There must be another reason for the operation being missing (delete api key) from the OpenAPI doc.

I'd also assume that the OP had the config set since his OpenAPI doc contained all the other ApiKey related server operations.

@florianmartens commented on GitHub (Mar 18, 2025): I have not tried the server sdk for deleting API keys yet. By my config definitely contains the plugin. ```ts export const auth = betterAuth({ ... plugins: [ openAPI(), organization({ organizationLimit: 1 }), apiKey({ rateLimit: { enabled: true, timeWindow: 1000 * 60 * 60 * 24, maxRequests: 5_000, }, apiKeyHeaders: ["x-api-key"], permissions: { defaultPermissions: () => { return { task: ["read", "write"], }; }, }, }), admin(), sso(), bearer(), ], databaseHooks: {...}, }); ``` There must be another reason for the operation being missing (delete api key) from the OpenAPI doc. I'd also assume that the OP had the config set since his OpenAPI doc contained all the other ApiKey related server operations.
Author
Owner

@ping-maxwell commented on GitHub (Mar 18, 2025):

We're working on a fix. In the mean time the server API to delete keys should work.

@ping-maxwell commented on GitHub (Mar 18, 2025): We're working on a fix. In the mean time the server API to delete keys should work.
Author
Owner

@ping-maxwell commented on GitHub (Mar 18, 2025):

https://github.com/better-auth/better-auth/pull/1858

@ping-maxwell commented on GitHub (Mar 18, 2025): https://github.com/better-auth/better-auth/pull/1858
Author
Owner

@erickleinde commented on GitHub (Mar 18, 2025):

sorry for the late reply, I have been away from my PC for the last few days.

Even though everything has already been said, I also wanted to say that I use the AuthClient.

config:

export const authClient = createAuthClient({
    baseURL: process.env.BETTER_AUTH_URL,
    plugins: [
        usernameClient(),
        adminClient(),
        apiKeyClient(),
    ]
})
const { error } = await authClient.apiKey.delete({
     keyId: apiKeyId
});
@erickleinde commented on GitHub (Mar 18, 2025): sorry for the late reply, I have been away from my PC for the last few days. Even though everything has already been said, I also wanted to say that I use the AuthClient. config: ```ts export const authClient = createAuthClient({ baseURL: process.env.BETTER_AUTH_URL, plugins: [ usernameClient(), adminClient(), apiKeyClient(), ] }) ``` ```ts const { error } = await authClient.apiKey.delete({ keyId: apiKeyId }); ```
Author
Owner

@florianmartens commented on GitHub (Mar 18, 2025):

@ping-maxwell Thanks for taking care of this.

Any chance the other two (more minor) issues could get addressed?

Issue I: The naming of the postgres table apikeys is also somewhat against the convention of the other tables. It should be api_keys I guess.

Issue II: I'm unable to access the inferred type of the ApiKey from both the server and client SDKs. I would have expected type T = typeof authClient.$Infer.ApiKey to work.

@florianmartens commented on GitHub (Mar 18, 2025): @ping-maxwell Thanks for taking care of this. Any chance the other two (more minor) issues could get addressed? > Issue I: The naming of the postgres table apikeys is also somewhat against the convention of the other tables. It should be api_keys I guess. > Issue II: I'm unable to access the inferred type of the ApiKey from both the server and client SDKs. I would have expected type T = typeof authClient.$Infer.ApiKey to work.
Author
Owner

@ping-maxwell commented on GitHub (Mar 18, 2025):

Issue I: The naming of the postgres table apikeys is also somewhat against the convention of the other tables. It should be api_keys I guess.

You should be able to pass schema into the apiKey plugin which allows you to rename the model.

Issue II: I'm unable to access the inferred type of the ApiKey from both the server and client SDKs. I would have expected type T = typeof authClient.$Infer.ApiKey to work.

There is currently a PR open to export api key types (https://github.com/better-auth/better-auth/pull/1859), but there isn't any way to infer the API key through the $Infer way yet.

@ping-maxwell commented on GitHub (Mar 18, 2025): > Issue I: The naming of the postgres table apikeys is also somewhat against the convention of the other tables. It should be api_keys I guess. You should be able to pass `schema` into the apiKey plugin which allows you to rename the model. > Issue II: I'm unable to access the inferred type of the ApiKey from both the server and client SDKs. I would have expected type T = typeof authClient.$Infer.ApiKey to work. There is currently a PR open to export api key types (https://github.com/better-auth/better-auth/pull/1859), but there isn't any way to infer the API key through the `$Infer` way yet.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#848