fix: bearer token interception for direct API calls

This commit is contained in:
Bereket Engida
2024-10-09 20:22:18 +03:00
parent 1dc573bca9
commit 0e77ed316e
5 changed files with 85 additions and 28 deletions

View File

@@ -1,5 +1,6 @@
import { betterAuth } from "better-auth";
import {
bearer,
organization,
passkey,
phoneNumber,
@@ -12,6 +13,7 @@ import { resend } from "./email/resend";
const from = process.env.BETTER_AUTH_EMAIL || "delivered@resend.dev";
const to = process.env.TEST_EMAIL || "";
export const auth = betterAuth({
database: new LibsqlDialect({
url: process.env.TURSO_DATABASE_URL || "",
@@ -80,6 +82,7 @@ export const auth = betterAuth({
},
}),
passkey(),
bearer()
],
socialProviders: {
github: {

View File

@@ -110,11 +110,33 @@ export function getEndpoints<
let api: Record<string, any> = {};
for (const [key, value] of Object.entries(endpoints)) {
api[key] = async (context: any) => {
/**
* TODO: move this to respond a json response
* instead of response object.
*/
const c = await ctx;
let c = await ctx;
for (const plugin of options.plugins || []) {
if (plugin.hooks?.before) {
for (const hook of plugin.hooks.before) {
const match = hook.matcher({
...value,
...context,
context: c,
});
if (match) {
const hookRes = await hook.handler({
...context,
context: {
...c,
...context.context,
},
});
if (hookRes && "context" in hookRes) {
c = {
...c,
...hookRes.context,
};
}
}
}
}
}
//@ts-ignore
const endpointRes = await value({
...context,

View File

@@ -19,7 +19,6 @@ type InferAPI<API> = Omit<
export const betterAuth = <O extends BetterAuthOptions>(options: O) => {
const authContext = init(options);
const { api } = getEndpoints(authContext, options);
type API = typeof api;
return {
handler: async (request: Request) => {

View File

@@ -3,7 +3,7 @@ import { bearer } from ".";
import { getTestInstance } from "../../test-utils/test-instance";
describe("bearer", async () => {
const { client, signInWithTestUser } = await getTestInstance({
const { client, signInWithTestUser, auth } = await getTestInstance({
plugins: [bearer()],
});
@@ -32,4 +32,15 @@ describe("bearer", async () => {
});
expect(sessions.data).toHaveLength(2);
});
it("should work on server actions", async () => {
const { res } = await signInWithTestUser();
token = res.data?.session.id || "";
const headers = new Headers();
headers.set("authorization", `Bearer ${token}`);
const session = await auth.api.getSession({
headers,
});
expect(session?.session.id).toBe(token);
});
});

View File

@@ -1,6 +1,4 @@
import { serializeSigned } from "better-call";
import { createAuthMiddleware } from "../../api/call";
import { BetterAuthError } from "../../error/better-auth-error";
import type { BetterAuthPlugin } from "../../types/plugins";
/**
@@ -9,25 +7,49 @@ import type { BetterAuthPlugin } from "../../types/plugins";
export const bearer = () => {
return {
id: "bearer",
async onRequest(request, ctx) {
const token = request.headers
.get("authorization")
?.replace("Bearer ", "");
hooks: {
before: [
{
matcher(context) {
return Boolean(
context.request?.headers.get("authorization") ||
context.headers?.get("authorization"),
);
},
handler: async (c) => {
const token =
c.request?.headers.get("authorization")?.replace("Bearer ", "") ||
c.headers?.get("authorization")?.replace("Bearer ", "");
if (!token) {
return;
}
const headers = request.headers || new Headers();
const signedToken = await serializeSigned("", token, ctx.secret);
headers.set(
"cookie",
`${ctx.authCookies.sessionToken.name}=${signedToken.replace("=", "")}`,
const signedToken = await serializeSigned(
"",
token,
c.context.secret,
);
if (c.request) {
c.request.headers.set(
"cookie",
`${
c.context.authCookies.sessionToken.name
}=${signedToken.replace("=", "")}`,
);
}
if (c.headers) {
c.headers.set(
"cookie",
`${
c.context.authCookies.sessionToken.name
}=${signedToken.replace("=", "")}`,
);
}
return {
request: new Request(request.url, {
method: request.method,
headers,
}),
context: c,
};
},
},
],
},
} satisfies BetterAuthPlugin;
};