import { Effect, Layer } from "effect"; import { IdentityProvider, type Principal, Unauthorized } from "@executor-js/api/server"; import { safeEqual } from "./serve-shared"; // --------------------------------------------------------------------------- // The local identity seam — the production implementation of the shared // `IdentityProvider` from `@executor-js/api/server` for the single-user local // daemon. // // Local is single-user: there is no account/org directory, and the executor it // serves is a single boot-built instance scoped to the working directory (see // `FixedExecutionProvider` in `app.ts`). There is exactly ONE credential — the // locally-minted bearer token (see `auth.ts`) — and exactly ONE Principal. So // this provider validates the `Authorization: Bearer ` header against the // boot token and resolves the one local Principal, or fails `Unauthorized`. // // This is the authoritative gate for the typed `/api` (the shared // `ExecutionStackMiddleware` calls `authenticate(request)` with the Web // `Request`). The Bun serve shell (`serve.ts`) additionally fast-path-rejects // unauthenticated requests and is the gate for the non-typed local surfaces // (`/mcp`, the MCP approval endpoint, the OAuth await poll) that never reach // this middleware — both read the SAME boot token. // --------------------------------------------------------------------------- /** * The single local Principal every authenticated request resolves to. Stable * across the process; the `local` ids identify the single-user daemon in * `AuthContext` and any "me"-style surfaces. The fixed executor's scope is * cwd-derived (in `app.ts`), independent of these ids. */ export const LOCAL_PRINCIPAL: Principal = { kind: "member", accountId: "local", organizationId: "local", organizationName: "Local", email: "local@localhost", name: "Local", avatarUrl: null, roles: [], }; const bearerToken = (headers: Headers): string | undefined => { const authorization = headers.get("authorization"); if (!authorization) return undefined; return authorization.toLowerCase().startsWith("bearer ") ? authorization.slice(7).trim() || undefined : undefined; }; // The OAuth provider callback is hit by the user's external browser, which // can't carry our bearer — the OAuth `state` (validated downstream by // completeOAuth) is the security gate. The Bun shell strips the `/api` prefix // before this layer runs, so the path here is `/oauth/callback`. This mirrors // the shell's `isUnauthenticatedOAuthCallbackPath` exemption (cloud/self-host // instead authenticate the callback via the same-origin session cookie). const isUnauthenticatedCallback = (request: Request): boolean => { // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: parsing a request URL that should always be valid here try { return /\/oauth\/callback(\/|$)/.test(new URL(request.url).pathname); } catch { return false; } }; /** * Build the local `IdentityProvider`: validate the request's bearer token * against the boot token and resolve `LOCAL_PRINCIPAL`, else fail `Unauthorized` * (rendered as a 401 by the middleware's failure strategy). A complete * `Layer` with no residual requirement, so the facade captures * it once at boot like self-host's. */ export const makeLocalIdentityLayer = (token: string): Layer.Layer => Layer.succeed(IdentityProvider)( IdentityProvider.of({ authenticate: (request) => { if (isUnauthenticatedCallback(request)) return Effect.succeed(LOCAL_PRINCIPAL); const presented = bearerToken(request.headers); return presented !== undefined && safeEqual(presented, token) ? Effect.succeed(LOCAL_PRINCIPAL) : Effect.fail(new Unauthorized()); }, }), );