fix: secure authentication request identity
Replace Better Auth's default trust of a caller-controlled X-Forwarded-For with a platform-owned client-address resolution boundary: direct mode (the safe default) trusts only the real socket peer, and an explicit trusted-proxy mode requires a header name, a concrete trusted-proxy list, and only honors a forwarded chain from an actual trusted peer. This closes a rate-limit bypass where rotating a spoofed header let a caller choose a fresh bucket on every request. Public sign-up is also disabled by default and requires an explicit typed opt-in, using Better Auth's own disableSignUp gate so no email-existence leak or second signup path is introduced. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5e09330001
commit
cafd513019
@@ -207,6 +207,25 @@ describe("Ekklesia API Hono application", () => {
|
||||
expect(JSON.stringify(body)).not.toContain("postgresql://");
|
||||
});
|
||||
|
||||
it("forces Cache-Control: no-store on every Better Auth response, including a successful one", async () => {
|
||||
const runtime = fakeRuntime({
|
||||
handleAuthRequest: vi.fn().mockResolvedValue(new Response("auth-ok", { status: 200 })),
|
||||
});
|
||||
const app = createApiApp({
|
||||
moduleRoutes: Object.freeze([]),
|
||||
moduleServices: fakeModuleServices(),
|
||||
authorization: fakeAuthorization({}),
|
||||
runtime,
|
||||
trustedOrigins: [trustedOrigin],
|
||||
});
|
||||
|
||||
const response = await app.request("/api/auth/sign-in/email", { method: "POST" });
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(await response.text()).toBe("auth-ok");
|
||||
expect(response.headers.get("cache-control")).toBe("no-store");
|
||||
});
|
||||
|
||||
it("has deterministic 404 behavior for an unknown route", async () => {
|
||||
const app = createApiApp({
|
||||
moduleRoutes: Object.freeze([]),
|
||||
|
||||
Reference in New Issue
Block a user