Spaces:
Running
Running
deploy(hf): sync szl-holdings/nexus@a0cd605f4d1021510a8e351de4016b2453e091e5 derived COPY set
8441695 verified Download src/lib/auth/verify.server.ts from SZLHOLDINGS/nexus: direct link, hf CLI and curl.
- Browser
- Download file 4.97 kB
-
https://huggingface.co/spaces/SZLHOLDINGS/nexus/resolve/main/src/lib/auth/verify.server.ts
- Command line
-
hf download hf://spaces/SZLHOLDINGS/nexus/src/lib/auth/verify.server.ts
-
curl -L -o verify.server.ts https://huggingface.co/spaces/SZLHOLDINGS/nexus/resolve/main/src/lib/auth/verify.server.ts
4.97 kB
| import { getRequest } from "@tanstack/react-start/server"; | |
| import { requestAuthPolicy } from "./federation"; | |
| import { gateIdentityEnabled } from "./gate-identity.server"; | |
| import { auth, authConfigured, authMode, authRefusal } from "./server"; | |
| /** | |
| * Server-side session resolution (server-only). | |
| * | |
| * Because this app runs its OWN Better Auth at same-origin `/api/auth/*`, the | |
| * session cookie is sent with every request to this app — server functions AND | |
| * SSR loaders included. So we resolve the user straight from the request cookies | |
| * via `auth.api.getSession` (no client-minted JWT needed). Never trust a | |
| * client-supplied user id — only the result of this verification. | |
| */ | |
| /** True when a real database is configured server-side. */ | |
| const databaseConfigured = Boolean(process.env.DATABASE_URL?.trim()); | |
| /** Re-export so callers can branch on it without importing `server.ts`. */ | |
| export { authConfigured, authRefusal }; | |
| /** How this request is authenticated (see `requestAuthPolicy` in `./federation`). */ | |
| function policy() { | |
| return requestAuthPolicy(authMode, { | |
| gateIdentity: gateIdentityEnabled(), | |
| databaseConfigured, | |
| }); | |
| } | |
| if (databaseConfigured && authMode === "disabled") { | |
| console.error( | |
| "[auth] DATABASE_URL is set but auth is disabled (VITE_AUTH_ENABLED=false) " + | |
| "— requireUserId() will reject every request (fail closed) rather than " + | |
| "share one dev user on a real database.", | |
| ); | |
| } | |
| /** Dev fallback user id, used only when auth is disabled (VITE_AUTH_ENABLED=false). */ | |
| export const DEV_USER_ID = "dev-user"; | |
| /** | |
| * Thrown by `requireUserId` when the caller has no valid session. Carries | |
| * `status: 401`; the message is a stable contract — match | |
| * `err.message === "Unauthorized"` client-side to send the visitor to sign-in. | |
| */ | |
| export class UnauthorizedError extends Error { | |
| readonly status = 401; | |
| constructor() { | |
| super("Unauthorized"); | |
| this.name = "UnauthorizedError"; | |
| } | |
| } | |
| /** | |
| * Thrown by `requireUserId` when federated sign-in was refused at startup (a | |
| * deployment without its own broker client; see `./federation`). Carries | |
| * `status: 503`: the server is misconfigured, so the visitor is not sent to a | |
| * sign-in that cannot work, and the shared dev user is never substituted. | |
| */ | |
| export class AuthUnavailableError extends Error { | |
| readonly status = 503; | |
| constructor(reason: string) { | |
| super(`Auth unavailable: ${reason}`); | |
| this.name = "AuthUnavailableError"; | |
| } | |
| } | |
| export type VerifiedUser = { id: string; email: string | null }; | |
| /** | |
| * Resolve the signed-in user from the current request, or `null` when auth isn't | |
| * configured / nobody is signed in. Safe to call from server functions and SSR | |
| * loaders. | |
| * | |
| * `bearerToken` is for the LIVE PREVIEW: the app runs in a partitioned iframe | |
| * whose cookies don't reach the server, so `authMiddleware` forwards the session | |
| * as a bearer token, which we present as `Authorization: Bearer …` (the `bearer` | |
| * plugin resolves it). When deployed no token is passed and the cookie is used. | |
| */ | |
| export async function getSessionUser( | |
| bearerToken?: string, | |
| ): Promise<VerifiedUser | null> { | |
| if (policy() !== "session") return null; | |
| const request = getRequest(); | |
| if (!request) return null; | |
| let headers = request.headers; | |
| if (bearerToken) { | |
| headers = new Headers(request.headers); | |
| headers.set("Authorization", `Bearer ${bearerToken}`); | |
| } | |
| const session = await auth.api.getSession({ headers }); | |
| if (!session?.user) return null; | |
| return { id: session.user.id, email: session.user.email ?? null }; | |
| } | |
| /** | |
| * Resolve the current user id for a server function, or throw when unauthorized. | |
| * Prefer `authMiddleware` (`./middleware`), which calls this for you. | |
| * - Auth enabled -> the verified session user id; throws | |
| * `UnauthorizedError` when signed out. Works in the sandbox preview too (real | |
| * sign-in via the baked preview client). | |
| * - Auth disabled (`VITE_AUTH_ENABLED=false`) + `DATABASE_URL` set -> throw (fail | |
| * closed): one shared dev user on a real database would let every visitor | |
| * read/write everyone's rows. | |
| * - Auth disabled + no database -> the shared dev user id. | |
| * - Federated sign-in refused (deployed without the per-app broker client) -> | |
| * throw `AuthUnavailableError`, with or without a database. Never the dev user. | |
| */ | |
| export async function requireUserId(bearerToken?: string): Promise<string> { | |
| switch (policy()) { | |
| case "refuse-federation": | |
| throw new AuthUnavailableError(authRefusal ?? "federated sign-in refused"); | |
| case "refuse-database": | |
| throw new Error( | |
| "Auth is disabled (VITE_AUTH_ENABLED=false) but DATABASE_URL is set — " + | |
| "refusing to fall back to the shared dev user against a real database.", | |
| ); | |
| case "dev-user": | |
| return DEV_USER_ID; | |
| case "session": | |
| break; | |
| } | |
| const user = await getSessionUser(bearerToken); | |
| if (!user) throw new UnauthorizedError(); | |
| return user.id; | |
| } | |