better-auth
Version:
The most comprehensive authentication framework for TypeScript.
75 lines (74 loc) • 2.85 kB
JavaScript
import { parseSetCookieHeader, setRequestCookie } from "../../cookies/cookie-utils.mjs";
import { PACKAGE_VERSION } from "../../version.mjs";
import { serializeSignedCookie } from "better-call";
import { createAuthMiddleware } from "@better-auth/core/api";
import { createHMAC } from "@better-auth/utils/hmac";
//#region src/plugins/bearer/index.ts
const BEARER_SCHEME = "bearer ";
function tryDecode(str) {
try {
return decodeURIComponent(str);
} catch {
return str;
}
}
/**
* Converts bearer token to session cookie
*/
const bearer = (options) => {
return {
id: "bearer",
version: PACKAGE_VERSION,
hooks: {
before: [{
matcher(context) {
return Boolean(context.request?.headers.get("authorization") || context.headers?.get("authorization"));
},
handler: createAuthMiddleware(async (c) => {
const authHeader = c.request?.headers.get("authorization") || c.headers?.get("Authorization");
if (!authHeader) return;
if (authHeader.slice(0, 7).toLowerCase() !== BEARER_SCHEME) return;
const token = authHeader.slice(7).trim();
if (!token) return;
let decodedToken;
if (token.includes(".")) decodedToken = token.includes("%") ? tryDecode(token) : token;
else {
if (options?.requireSignature) return;
decodedToken = tryDecode((await serializeSignedCookie("", token, c.context.secret)).replace("=", ""));
}
try {
if (!await createHMAC("SHA-256", "base64urlnopad").verify(c.context.secret, decodedToken.split(".")[0], decodedToken.split(".")[1])) return;
} catch {
return;
}
const existingHeaders = c.request?.headers || c.headers;
const headers = new Headers({ ...Object.fromEntries(existingHeaders?.entries()) });
setRequestCookie(headers, c.context.authCookies.sessionToken.name, decodedToken);
return { context: { headers } };
})
}],
after: [{
matcher(context) {
return true;
},
handler: createAuthMiddleware(async (ctx) => {
const setCookie = ctx.context.responseHeaders?.get("set-cookie");
if (!setCookie) return;
const parsedCookies = parseSetCookieHeader(setCookie);
const cookieName = ctx.context.authCookies.sessionToken.name;
const sessionCookie = parsedCookies.get(cookieName);
if (!sessionCookie || !sessionCookie.value || sessionCookie["max-age"] === 0) return;
const token = sessionCookie.value;
const exposedHeaders = ctx.context.responseHeaders?.get("access-control-expose-headers") || "";
const headersSet = new Set(exposedHeaders.split(",").map((header) => header.trim()).filter(Boolean));
headersSet.add("set-auth-token");
ctx.setHeader("set-auth-token", token);
ctx.setHeader("Access-Control-Expose-Headers", Array.from(headersSet).join(", "));
})
}]
},
options
};
};
//#endregion
export { bearer };