Mismatch in apiKey returned from call, and the one written in DB #1188

Closed
opened 2026-03-13 08:27:09 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @tunnckoCore on GitHub (May 10, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

A basic setup with Bun, Drizzle, SQLite, and playing with the authClient (with the auth.api too)

const userId = crypto.randomUUID();
const expiresIn = 60 * 60 * 24 * 365; // 1 year

const result = await authClient.apiKey.create({
  expiresIn,
  metadata: {
    description: `API key for premium user ${userId}`, // description of the API key
    tier: 'premium',
  },
  name: 'My API Key',
  rateLimitEnabled: true,
  userId,
});

console.log(result);

From the screenshot, you can see my terminal output of above, and behind it is the actual result in the database seen from Drizzle Studio.

Image

Current vs. Expected behavior

The key in the database doesn't match the one returned from client call. What's even more tellin is that the start column in the database also does not match the actual start of the written key in the database, but matches the start of the returned key.

What version of Better Auth are you using?

^1.2.7

Provide environment information

- Linux
- Brave latest Beta (not important, i'm running on terminal)

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

Backend, Package, Client

Auth config (if applicable)

import { createId, init as createInit } from '@paralleldrive/cuid2';
import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { anonymous, apiKey } from 'better-auth/plugins';

import { db } from './db.ts'; // your drizzle instance

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: 'sqlite' }),
  emailAndPassword: {
    enabled: true,

    passwordComplexity: {
      minLength: 3,
      // requireLowercase: true,
      // requireNumbers: true,
      // requireSpecial: true,
      // requireUppercase: true,
    },
  },
  plugins: [
    anonymous(),
    apiKey({
      defaultPrefix: 'wgw_',
      enableMetadata: true,
    }),
  ],
});

Additional context

I also tried with a custom key generator

customKeyGenerator: () => createInit({ length: 8 })(), // createInit is cuid2

We can see again that one is return and it's totally another and not even respecting that it's a custom key;

Image

Doesn't seem to be respecting if i set defaultKeyLength neither, the key (default or not) continue to be with a fixed size.

Image

Originally created by @tunnckoCore on GitHub (May 10, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce A basic setup with Bun, Drizzle, SQLite, and playing with the authClient (with the `auth.api` too) ```ts const userId = crypto.randomUUID(); const expiresIn = 60 * 60 * 24 * 365; // 1 year const result = await authClient.apiKey.create({ expiresIn, metadata: { description: `API key for premium user ${userId}`, // description of the API key tier: 'premium', }, name: 'My API Key', rateLimitEnabled: true, userId, }); console.log(result); ``` From the screenshot, you can see my terminal output of above, and behind it is the actual result in the database seen from Drizzle Studio. ![Image](https://github.com/user-attachments/assets/9d70b28d-72dd-49c1-bc19-6ca43b1e4d27) ### Current vs. Expected behavior The key in the database doesn't match the one returned from client call. What's even more tellin is that the `start` column in the database also does not match the actual start of the written `key` in the database, but matches the start of the returned key. ### What version of Better Auth are you using? ^1.2.7 ### Provide environment information ```bash - Linux - Brave latest Beta (not important, i'm running on terminal) ``` ### Which area(s) are affected? (Select all that apply) Backend, Package, Client ### Auth config (if applicable) ```typescript import { createId, init as createInit } from '@paralleldrive/cuid2'; import { betterAuth } from 'better-auth'; import { drizzleAdapter } from 'better-auth/adapters/drizzle'; import { anonymous, apiKey } from 'better-auth/plugins'; import { db } from './db.ts'; // your drizzle instance export const auth = betterAuth({ database: drizzleAdapter(db, { provider: 'sqlite' }), emailAndPassword: { enabled: true, passwordComplexity: { minLength: 3, // requireLowercase: true, // requireNumbers: true, // requireSpecial: true, // requireUppercase: true, }, }, plugins: [ anonymous(), apiKey({ defaultPrefix: 'wgw_', enableMetadata: true, }), ], }); ``` ### Additional context I also tried with a custom key generator ```ts customKeyGenerator: () => createInit({ length: 8 })(), // createInit is cuid2 ``` We can see again that one is return and it's totally another and not even respecting that it's a custom key; ![Image](https://github.com/user-attachments/assets/589b43f7-ee7d-430d-ae45-bdaf4e64bc73) Doesn't seem to be respecting if i set `defaultKeyLength` neither, the key (default or not) continue to be with a fixed size. ![Image](https://github.com/user-attachments/assets/e1636227-fb8f-4508-9ce6-44258cea9f2a)
Author
Owner

@ping-maxwell commented on GitHub (May 28, 2025):

We hash API keys, the same way we hash passwords.
The returned value seen in your console is the real API key which you can then use to call verifyApiKey.

@ping-maxwell commented on GitHub (May 28, 2025): We hash API keys, the same way we hash passwords. The returned value seen in your console is the real API key which you can then use to call verifyApiKey.
Author
Owner

@tunnckoCore commented on GitHub (May 28, 2025):

Hmm. Ookay, that makes sense.

@tunnckoCore commented on GitHub (May 28, 2025): Hmm. Ookay, that makes sense.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1188