Skip to content

Commit d384ee6

Browse files
committed
fix(api-key): calling client on server side (#4777)
1 parent 39c21cf commit d384ee6

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

e2e/smoke/test/ssr.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { betterAuth } from "better-auth";
2+
import { describe, test } from "node:test";
3+
import { DatabaseSync } from "node:sqlite";
4+
import { apiKey } from "better-auth/plugins";
5+
import { createAuthClient } from "better-auth/client";
6+
import { apiKeyClient } from "better-auth/client/plugins";
7+
import { getMigrations } from "better-auth/db";
8+
import assert from "node:assert/strict";
9+
10+
describe("server side client", () => {
11+
test("can use api key on server side", async () => {
12+
const database = new DatabaseSync(":memory:");
13+
const auth = betterAuth({
14+
baseURL: "http://localhost:3000",
15+
database,
16+
socialProviders: {
17+
github: {
18+
clientId: process.env.GITHUB_CLIENT_ID as string,
19+
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
20+
},
21+
},
22+
emailAndPassword: {
23+
enabled: true,
24+
},
25+
plugins: [
26+
apiKey({
27+
rateLimit: {
28+
enabled: false,
29+
},
30+
}),
31+
],
32+
});
33+
34+
const { runMigrations } = await getMigrations(auth.options);
35+
await runMigrations();
36+
37+
const authClient: ReturnType<typeof createAuthClient> = createAuthClient({
38+
baseURL: "http://localhost:3000",
39+
plugins: [apiKeyClient()],
40+
fetchOptions: {
41+
customFetchImpl: async (url, init) => {
42+
return auth.handler(new Request(url, init));
43+
},
44+
},
45+
});
46+
47+
const { user } = await auth.api.signUpEmail({
48+
body: {
49+
name: "Alex",
50+
email: "alex@test.com",
51+
password: "hello123",
52+
},
53+
});
54+
55+
const { key, id, userId } = await auth.api.createApiKey({
56+
body: {
57+
name: "my-api-key",
58+
userId: user.id,
59+
},
60+
});
61+
62+
const ret = database.prepare(`SELECT * FROM apiKey;`).all();
63+
assert.equal(ret.length, 1);
64+
const first = ret.at(-1)!;
65+
assert.equal(first.id, id);
66+
assert.equal(first.userId, userId);
67+
68+
await authClient.getSession({
69+
fetchOptions: {
70+
headers: {
71+
"x-api-key": key,
72+
},
73+
},
74+
});
75+
});
76+
});

packages/better-auth/src/api/to-auth-endpoints.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
APIError,
3-
toResponse,
43
type EndpointContext,
54
type EndpointOptions,
65
type InputContext,
6+
toResponse,
77
} from "better-call";
88
import type { AuthEndpoint, AuthMiddleware } from "./call";
99
import type { AuthContext, HookEndpointContext } from "../types";
@@ -81,7 +81,16 @@ export function toAuthEndpoints<E extends Record<string, AuthEndpoint>>(
8181
internalContext = defuReplaceArrays(rest, internalContext);
8282
} else if (before) {
8383
/* Return before hook response if it's anything other than a context return */
84-
return before;
84+
return context?.asResponse
85+
? toResponse(before, {
86+
headers: context?.headers,
87+
})
88+
: context?.returnHeaders
89+
? {
90+
headers: context?.headers,
91+
response: before,
92+
}
93+
: before;
8594
}
8695

8796
internalContext.asResponse = false;

0 commit comments

Comments
 (0)