f942e4e597
Backend: - Port auth_middleware, csrf_middleware, langgraph_auth, routers/auth - Port authz decorator (owner_filter_key defaults to 'owner_id') - Merge app.py: register AuthMiddleware + CSRFMiddleware + CORS, add _ensure_admin_user lifespan hook, _migrate_orphaned_threads helper, register auth router - Merge deps.py: add get_local_provider, get_current_user_from_request, get_optional_user_from_request; keep get_current_user as thin str|None adapter for feedback router - langgraph.json: add auth path pointing to langgraph_auth.py:auth - Rename metadata['user_id'] -> metadata['owner_id'] in langgraph_auth (both metadata write and LangGraph filter dict) + test fixtures Frontend: - Delete better-auth library and api catch-all route - Remove better-auth npm dependency and env vars (BETTER_AUTH_SECRET, BETTER_AUTH_GITHUB_*) from env.js - Port frontend/src/core/auth/* (AuthProvider, gateway-config, proxy-policy, server-side getServerSideUser, types) - Port frontend/src/core/api/fetcher.ts - Port (auth)/layout, (auth)/login, (auth)/setup pages - Rewrite workspace/layout.tsx as server component that calls getServerSideUser and wraps in AuthProvider - Port workspace/workspace-content.tsx for the client-side sidebar logic Tests: - Port 5 auth test files (test_auth, test_auth_middleware, test_auth_type_system, test_ensure_admin, test_langgraph_auth) - 176 auth tests PASS After this commit: login/logout/registration flow works, but persistence layer does not yet filter by owner_id. Commit 4 closes that gap.
40 lines
938 B
TypeScript
40 lines
938 B
TypeScript
import { buildLoginUrl } from "@/core/auth/types";
|
|
|
|
/**
|
|
* Fetch with credentials. Automatically redirects to login on 401.
|
|
*/
|
|
export async function fetchWithAuth(
|
|
input: RequestInfo | string,
|
|
init?: RequestInit,
|
|
): Promise<Response> {
|
|
const url = typeof input === "string" ? input : input.url;
|
|
const res = await fetch(url, {
|
|
...init,
|
|
credentials: "include",
|
|
});
|
|
|
|
if (res.status === 401) {
|
|
window.location.href = buildLoginUrl(window.location.pathname);
|
|
throw new Error("Unauthorized");
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Build headers for CSRF-protected requests
|
|
* Per RFC-001: Double Submit Cookie pattern
|
|
*/
|
|
export function getCsrfHeaders(): HeadersInit {
|
|
const token = getCsrfToken();
|
|
return token ? { "X-CSRF-Token": token } : {};
|
|
}
|
|
|
|
/**
|
|
* Get CSRF token from cookie
|
|
*/
|
|
function getCsrfToken(): string | null {
|
|
const match = /csrf_token=([^;]+)/.exec(document.cookie);
|
|
return match?.[1] ?? null;
|
|
}
|