Files
codey.lol/src/hooks/requireAuthHook.js

84 lines
2.5 KiB
JavaScript
Raw Normal View History

2025-08-28 11:15:17 -04:00
// requireAuthHook.js
import { API_URL } from "@/config";
// WeakMap to cache auth promises per Astro context (request)
const authCache = new WeakMap();
2025-08-28 11:15:17 -04:00
export const requireAuthHook = async (Astro) => {
// Check if we already have a cached promise for this request
if (authCache.has(Astro)) {
return authCache.get(Astro);
}
// Create a promise and cache it immediately to prevent race conditions
const authPromise = performAuth(Astro);
authCache.set(Astro, authPromise);
// Return the promise - all callers will await the same promise
return authPromise;
};
async function performAuth(Astro) {
try {
2025-08-28 11:15:17 -04:00
const cookieHeader = Astro.request.headers.get("cookie") ?? "";
let res = await fetch(`${API_URL}/auth/id`, {
headers: { Cookie: cookieHeader },
credentials: "include",
});
if (res.status === 401) {
const refreshRes = await fetch(`${API_URL}/auth/refresh`, {
method: "POST",
headers: { Cookie: cookieHeader },
credentials: "include",
});
if (!refreshRes.ok) {
console.error("Token refresh failed", refreshRes.status);
2025-08-28 11:15:17 -04:00
return null;
}
// Get all Set-Cookie headers (getSetCookie returns an array)
let setCookies = [];
if (typeof refreshRes.headers.getSetCookie === 'function') {
setCookies = refreshRes.headers.getSetCookie();
} else {
// Fallback for older Node versions
const setCookieHeader = refreshRes.headers.get("set-cookie");
if (setCookieHeader) {
// Split on comma followed by a cookie name (word=), avoiding splitting on Expires dates
setCookies = setCookieHeader.split(/,(?=\s*[a-zA-Z_][a-zA-Z0-9_]*=)/);
}
}
if (setCookies.length === 0) {
console.error("No set-cookie header found in refresh response");
return null;
}
2025-08-28 11:15:17 -04:00
// Forward cookies to client
setCookies.forEach((c) => Astro.response.headers.append("set-cookie", c.trim()));
// Build new cookie header for the retry request
const newCookieHeader = setCookies.map(c => c.split(";")[0].trim()).join("; ");
2025-08-28 11:15:17 -04:00
res = await fetch(`${API_URL}/auth/id`, {
headers: { Cookie: newCookieHeader },
credentials: "include",
});
}
2025-08-28 11:15:17 -04:00
if (!res.ok) {
console.error("Failed to fetch user ID after token refresh", res.status);
2025-08-28 11:15:17 -04:00
return null;
}
2025-08-28 11:15:17 -04:00
const user = await res.json();
return user;
} catch (err) {
console.error("[SSR] requireAuthHook error:", err);
return null;
}
}