[GH-ISSUE #4080] 1.3.7 broke auth with existing API keys #9822

Closed
opened 2026-04-13 05:33:27 -05:00 by GiteaMirror · 12 comments
Owner

Originally created by @tehnrd on GitHub (Aug 19, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/4080

Originally assigned to: @himself65 on GitHub.

Existing API Keys have stopped working with 1.3.7.

This is with SvelteKit, I haven't been able to test other frameworks.

This feels like a critical issue.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Use an API Key for auth on 1.3.6, works.

Upgraded to 1.3.7.

Use the same API Key, it starts throwing:

[APIError] {
  status: 'UNAUTHORIZED',
  body: undefined,
  headers: {},
  statusCode: 401
}

Current vs. Expected behavior

API Keys should continue to work after package upgrades.

What version of Better Auth are you using?

1.3.7

System info

System:
    OS: macOS 15.5
    CPU: (10) arm64 Apple M1 Pro
    Memory: 227.45 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Browsers:
    Chrome: 139.0.7258.128
    Safari: 18.5

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

Backend

Auth config (if applicable)


Additional context

Probably related to b386d5edc1 but I haven't had time to investigate.

Originally created by @tehnrd on GitHub (Aug 19, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/4080 Originally assigned to: @himself65 on GitHub. Existing API Keys have stopped working with 1.3.7. This is with SvelteKit, I haven't been able to test other frameworks. This feels like a critical issue. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce Use an API Key for auth on 1.3.6, works. Upgraded to 1.3.7. Use the same API Key, it starts throwing: ``` [APIError] { status: 'UNAUTHORIZED', body: undefined, headers: {}, statusCode: 401 } ``` ### Current vs. Expected behavior API Keys should continue to work after package upgrades. ### What version of Better Auth are you using? 1.3.7 ### System info ```bash System: OS: macOS 15.5 CPU: (10) arm64 Apple M1 Pro Memory: 227.45 MB / 32.00 GB Shell: 5.9 - /bin/zsh Browsers: Chrome: 139.0.7258.128 Safari: 18.5 ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript ``` ### Additional context Probably related to https://github.com/better-auth/better-auth/commit/b386d5edc13b94adff3b2e39c2fd131ae2c786a2 but I haven't had time to investigate.
GiteaMirror added the lockedbug labels 2026-04-13 05:33:27 -05:00
Author
Owner

@ping-maxwell commented on GitHub (Aug 19, 2025):

Hey do you know which API endpoint specifically is throwing the error?

<!-- gh-comment-id:3201715684 --> @ping-maxwell commented on GitHub (Aug 19, 2025): Hey do you know which API endpoint specifically is throwing the error?
Author
Owner

@tehnrd commented on GitHub (Aug 19, 2025):

Not yet. Do you know the best way to identify this? console.trace() isn't showing anything helpful or specific to better-auth. It's all server-side, so methods are being called directly and not through the HTTP router.

<!-- gh-comment-id:3201743847 --> @tehnrd commented on GitHub (Aug 19, 2025): Not yet. Do you know the best way to identify this? console.trace() isn't showing anything helpful or specific to better-auth. It's all server-side, so methods are being called directly and not through the HTTP router.
Author
Owner

@ping-maxwell commented on GitHub (Aug 19, 2025):

As far as I know when checking changes between 1.3.6 and 1.3.7 is the logic change in the x-api-key in get session requests, but I thought there was a custom error message if it's unauthenticated, which I don't see in your issue post

EDIT: Looks like @himself65 is onto something 👀

<!-- gh-comment-id:3201845798 --> @ping-maxwell commented on GitHub (Aug 19, 2025): As far as I know when checking changes between 1.3.6 and 1.3.7 is the logic change in the `x-api-key` in get session requests, but I thought there was a custom error message if it's unauthenticated, which I don't see in your issue post EDIT: Looks like @himself65 is onto something 👀
Author
Owner

@himself65 commented on GitHub (Aug 19, 2025):

Not yet. Do you know the best way to identify this? console.trace() isn't showing anything helpful or specific to better-auth. It's all server-side, so methods are being called directly and not through the HTTP router.

In the latest version we have a errorWithStack property in the APIError

<!-- gh-comment-id:3201901298 --> @himself65 commented on GitHub (Aug 19, 2025): > Not yet. Do you know the best way to identify this? console.trace() isn't showing anything helpful or specific to better-auth. It's all server-side, so methods are being called directly and not through the HTTP router. In the latest version we have a errorWithStack property in the APIError
Author
Owner

@himself65 commented on GitHub (Aug 19, 2025):

As far as I know when checking changes between 1.3.6 and 1.3.7 is the logic change in the x-api-key in get session requests, but I thought there was a custom error message if it's unauthenticated, which I don't see in your issue post

EDIT: Looks like @himself65 is onto something 👀

Not sure if im correct but the latest code only check get-session endpoint

<!-- gh-comment-id:3201906227 --> @himself65 commented on GitHub (Aug 19, 2025): > As far as I know when checking changes between 1.3.6 and 1.3.7 is the logic change in the `x-api-key` in get session requests, but I thought there was a custom error message if it's unauthenticated, which I don't see in your issue post > > EDIT: Looks like [@himself65](https://github.com/himself65) is onto something 👀 Not sure if im correct but the latest code only check get-session endpoint
Author
Owner

@tehnrd commented on GitHub (Aug 19, 2025):

@himself65 I can confirm that your PR fixed the issue for me.

<!-- gh-comment-id:3202040430 --> @tehnrd commented on GitHub (Aug 19, 2025): @himself65 I can confirm that your PR fixed the issue for me.
Author
Owner

@himself65 commented on GitHub (Aug 19, 2025):

thanks. im gonna merge it soon

<!-- gh-comment-id:3202265054 --> @himself65 commented on GitHub (Aug 19, 2025): thanks. im gonna merge it soon
Author
Owner

@himself65 commented on GitHub (Aug 20, 2025):

@tehnrd I'm trying to create a minimal reproduce code from real production. Can you provide that?

<!-- gh-comment-id:3203704822 --> @himself65 commented on GitHub (Aug 20, 2025): @tehnrd I'm trying to create a minimal reproduce code from real production. Can you provide that?
Author
Owner

@tehnrd commented on GitHub (Aug 20, 2025):

It may take me a few days to get a full repro. I know this isn't what you asked for, but maybe something is better than nothing for now.

Assumes a user has been created and an API key generated for the user.

In a sveltekit project:

server.hooks.ts

import type { Handle } from '@sveltejs/kit';
import { svelteKitHandler } from 'better-auth/svelte-kit';
import { building } from '$app/environment';
import { betterAuth } from 'better-auth';
import { apiKey } from 'better-auth/plugins';

const auth = betterAuth({
plugins: [apiKey({})],
...other config like db adapter
});

export const handle: Handle = async ({ event, resolve }) => {	// Get the user session if it exists, this will be null if the user is not authenticated
	const session = await auth.api.getSession({
		headers: event.request.headers
	});

	// Call the SvelteKit handler to process the request
	const response = await svelteKitHandler({ event, resolve, auth, building });

	return response;
});

/app/src/routes/api/user/info/+server.ts

import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ locals }) => {
	return json({
		user: locals.user
	});
};

Start the server with npm run dev, then throw a get request at it with the API key:

curl -X GET 'https://localhost:5173/api/user/info' -H 'x-api-key: huPIlEOWHLdq...' -k
<!-- gh-comment-id:3203974837 --> @tehnrd commented on GitHub (Aug 20, 2025): It may take me a few days to get a full repro. I know this isn't what you asked for, but maybe something is better than nothing for now. Assumes a user has been created and an API key generated for the user. In a sveltekit project: server.hooks.ts ```typescript import type { Handle } from '@sveltejs/kit'; import { svelteKitHandler } from 'better-auth/svelte-kit'; import { building } from '$app/environment'; import { betterAuth } from 'better-auth'; import { apiKey } from 'better-auth/plugins'; const auth = betterAuth({ plugins: [apiKey({})], ...other config like db adapter }); export const handle: Handle = async ({ event, resolve }) => { // Get the user session if it exists, this will be null if the user is not authenticated const session = await auth.api.getSession({ headers: event.request.headers }); // Call the SvelteKit handler to process the request const response = await svelteKitHandler({ event, resolve, auth, building }); return response; }); ``` /app/src/routes/api/user/info/+server.ts ``` import { json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; export const GET: RequestHandler = async ({ locals }) => { return json({ user: locals.user }); }; ``` Start the server with npm run dev, then throw a get request at it with the API key: ``` curl -X GET 'https://localhost:5173/api/user/info' -H 'x-api-key: huPIlEOWHLdq...' -k ```
Author
Owner

@himself65 commented on GitHub (Aug 20, 2025):

It may take me a few days to get a full repro. I know this isn't what you asked for, but maybe something is better than nothing for now.

Assumes a user has been created and an API key generated for the user.

In a sveltekit project:

server.hooks.ts

import type { Handle } from '@sveltejs/kit';
import { svelteKitHandler } from 'better-auth/svelte-kit';
import { building } from '$app/environment';
import { betterAuth } from 'better-auth';
import { apiKey } from 'better-auth/plugins';

const auth = betterAuth({
plugins: [apiKey({})],
...other config like db adapter
});

export const handle: Handle = async ({ event, resolve }) => { // Get the user session if it exists, this will be null if the user is not authenticated
const session = await auth.api.getSession({
headers: event.request.headers
});

// Call the SvelteKit handler to process the request
const response = await svelteKitHandler({ event, resolve, auth, building });

return response;
});
/app/src/routes/api/user/info/+server.ts

import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ locals }) => {
	return json({
		user: locals.user
	});
};

Start the server with npm run dev, then throw a get request at it with the API key:

curl -X GET 'https://localhost:5173/api/user/info' -H 'x-api-key: huPIlEOWHLdq...' -k

Ok thank u. this is enough for me. I think I know why it is happening.

<!-- gh-comment-id:3204016631 --> @himself65 commented on GitHub (Aug 20, 2025): > It may take me a few days to get a full repro. I know this isn't what you asked for, but maybe something is better than nothing for now. > > Assumes a user has been created and an API key generated for the user. > > In a sveltekit project: > > server.hooks.ts > > import type { Handle } from '@sveltejs/kit'; > import { svelteKitHandler } from 'better-auth/svelte-kit'; > import { building } from '$app/environment'; > import { betterAuth } from 'better-auth'; > import { apiKey } from 'better-auth/plugins'; > > const auth = betterAuth({ > plugins: [apiKey({})], > ...other config like db adapter > }); > > export const handle: Handle = async ({ event, resolve }) => { // Get the user session if it exists, this will be null if the user is not authenticated > const session = await auth.api.getSession({ > headers: event.request.headers > }); > > // Call the SvelteKit handler to process the request > const response = await svelteKitHandler({ event, resolve, auth, building }); > > return response; > }); > /app/src/routes/api/user/info/+server.ts > > ``` > import { json } from '@sveltejs/kit'; > import type { RequestHandler } from './$types'; > > export const GET: RequestHandler = async ({ locals }) => { > return json({ > user: locals.user > }); > }; > ``` > > Start the server with npm run dev, then throw a get request at it with the API key: > > ``` > curl -X GET 'https://localhost:5173/api/user/info' -H 'x-api-key: huPIlEOWHLdq...' -k > ``` Ok thank u. this is enough for me. I think I know why it is happening.
Author
Owner

@tehnrd commented on GitHub (Aug 20, 2025):

Ok great! Let me know if you do end up needing more and I can work on that.

<!-- gh-comment-id:3204039111 --> @tehnrd commented on GitHub (Aug 20, 2025): Ok great! Let me know if you do end up needing more and I can work on that.
Author
Owner

@tehnrd commented on GitHub (Oct 18, 2025):

...this bug has regressed...will open a new issue, not sure exactly what version regressed it.

<!-- gh-comment-id:3417667252 --> @tehnrd commented on GitHub (Oct 18, 2025): ...this bug has regressed...will open a new issue, not sure exactly what version regressed it.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9822