1.4 KB42 lines
Blame
1// SSR-side fetch helpers that forward the user's auth token to the API.
2//
3// Auth lives in `grove_hub_token` (issued by hub-api, JWT verified by both
4// hub-api and the grove api with the shared JWT_SECRET). On the client it
5// also lives in localStorage but Next.js server components can only see
6// the cookie. Without forwarding it, every SSR fetch is anonymous, which
7// makes private repos look like 404s to their actual owners.
8
9import { cookies } from "next/headers";
10import { groveApiUrl } from "./utils";
11
12const TOKEN_COOKIE = "grove_hub_token";
13
14/** Read the user's bearer token from cookies. Returns null if missing. */
15export async function readAuthToken(): Promise<string | null> {
16 const store = await cookies();
17 return store.get(TOKEN_COOKIE)?.value ?? null;
18}
19
20/** Build auth headers for a server-side fetch. Empty if no token. */
21export async function authHeaders(): Promise<Record<string, string>> {
22 const token = await readAuthToken();
23 return token ? { authorization: `Bearer ${token}` } : {};
24}
25
26/** Fetch a Grove API path forwarding the user's auth token. Defaults to
27 * no-store so per-user data isn't cached across requests. */
28export async function serverFetch(
29 path: string,
30 init: RequestInit = {},
31): Promise<Response> {
32 const headers = {
33 ...(init.headers ?? {}),
34 ...(await authHeaders()),
35 };
36 return fetch(`${groveApiUrl}${path}`, {
37 cache: "no-store",
38 ...init,
39 headers,
40 });
41}
42