Files
zopu-code/apps/web/src/lib/auth.server.ts
Miniputer 1855735245 Auth flow refactor, project requests, and routing updates
- Add server-side auth token loader (auth.server.ts) with SSR cookie forwarding
- Add project-requests client for explicit/signal/existing issue dispatch
- Refactor auth layout and app layout for SSR auth gating
- Update auth-client and auth-provider for convex token flow
- Extend project-issue primitives with request result schema
- Wire projectIssues backend mutation for request handling
- Update slice-one page and project-workspace hook
- Adjust routes (remove unused), Caddy config, and env templates
2026-07-27 18:47:43 +05:30

65 lines
1.7 KiB
TypeScript

import { env } from "@code/env/web";
import { redirect } from "react-router";
interface AuthLoaderData {
readonly token: string | null;
}
const tokenUrl = new URL("/api/auth/convex/token", env.VITE_AUTH_URL);
export const loadAuthToken = async (
request: Request
): Promise<AuthLoaderData> => {
const cookie = request.headers.get("cookie");
if (!cookie) {
return { token: null };
}
const headers = new Headers({ cookie });
headers.set("host", tokenUrl.host);
const response = await fetch(tokenUrl, { headers });
if (response.status === 401) {
return { token: null };
}
if (!response.ok) {
throw new Response("Authentication service unavailable", { status: 503 });
}
const payload: unknown = await response.json();
if (
typeof payload !== "object" ||
payload === null ||
!("token" in payload) ||
typeof payload.token !== "string"
) {
throw new Response("Authentication service returned an invalid response", {
status: 502,
});
}
return { token: payload.token };
};
export const requireAuthToken = async (
request: Request
): Promise<AuthLoaderData> => {
const auth = await loadAuthToken(request);
if (!auth.token) {
const requestUrl = new URL(request.url);
const returnTo = `${requestUrl.pathname}${requestUrl.search}`;
throw redirect(`/login?returnTo=${encodeURIComponent(returnTo)}`);
}
return auth;
};
export const redirectAuthenticated = async (
request: Request
): Promise<AuthLoaderData> => {
const auth = await loadAuthToken(request);
if (auth.token) {
const requestUrl = new URL(request.url);
const returnTo = requestUrl.searchParams.get("returnTo");
throw redirect(returnTo?.startsWith("/") ? returnTo : "/");
}
return auth;
};