Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions apps/cloud/src/coexistence/identity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/** Private rollout boundary; existing auth providers still own credential and membership checks. */
import { timingSafeEqual } from "node:crypto";
import { Effect, Predicate } from "effect";
import { McpAuthProvider } from "@executor-js/host-mcp";
import { cloudMcpAuth } from "../mcp/auth-provider";
import { prepareMcpOrgScope } from "../mcp/mount";
import { CoreSharedServices, WorkOSClient } from "../auth/workos";
import { authorizeOrganizationSelector } from "../auth/organization";
import { RequestScopedServicesLive } from "../api/layers";

const reply = (body: unknown, status = 200): Response =>
Response.json(body, {
status,
headers: { "cache-control": "no-store" },
});
const keyMatches = (expected: string, actual: string): boolean => {
const encoder = new TextEncoder();
const left = encoder.encode(expected);
const right = encoder.encode(actual);
return left.length === right.length && timingSafeEqual(left, right);
};

/** Disabled unless explicitly configured. It never returns a token, email, or credential. */
export const coexistenceIdentity = (
request: Request,
secret: string | undefined,
): Promise<Response> => {
const supplied = request.headers.get("x-executor-coexistence-key");
if (!secret || secret.length < 32 || !supplied || !keyMatches(secret, supplied))
return Promise.resolve(reply({ error: "Not found" }, 404));
if (request.method !== "GET") return Promise.resolve(reply({ error: "Method not allowed" }, 405));
const url = new URL(request.url);
const kind = url.searchParams.get("kind");
const selector = url.searchParams.get("organization");
const mcp = Effect.gen(function* () {
const auth = yield* McpAuthProvider;
const target = new URL(
selector === null ? "/mcp" : `/${encodeURIComponent(selector)}/mcp`,
request.url,
);
const outcome = yield* auth.authenticate(
prepareMcpOrgScope(new Request(target, { headers: request.headers })),
);
if (Predicate.isTagged(outcome, "Authenticated")) {
const principal = outcome.principal;
return reply({
userId: principal.accountId,
organizationId: principal.organizationId,
organizationSlug: principal.organizationSlug ?? null,
role: principal.orgRole,
});
}
if (Predicate.isTagged(outcome, "Unauthorized")) return reply({ error: "Unauthorized" }, 401);
if (Predicate.isTagged(outcome, "Forbidden")) return reply({ error: "Forbidden" }, 403);
return reply({ error: "Authentication unavailable" }, 503);
}).pipe(Effect.provide(cloudMcpAuth));
const browser = Effect.gen(function* () {
const workos = yield* WorkOSClient;
const session = yield* workos.authenticateRequest(request);
if (session === null) return reply({ error: "Unauthorized" }, 401);
const organization = selector ?? session.organizationId;
if (!organization) return reply({ error: "Organization required" }, 403);
const membership = yield* authorizeOrganizationSelector(session.userId, organization);
if (membership === null) return reply({ error: "Forbidden" }, 403);
return reply({
userId: session.userId,
organizationId: membership.id,
organizationSlug: membership.slug ?? null,
role: membership.memberRole,
});
}).pipe(Effect.provide(RequestScopedServicesLive), Effect.provide(CoreSharedServices));
if (kind !== "mcp" && kind !== "browser")
return Promise.resolve(reply({ error: "Invalid identity kind" }, 400));
return Effect.runPromise(
(kind === "mcp" ? mcp : browser).pipe(
Effect.scoped,
Effect.catchCause(() => Effect.succeed(reply({ error: "Authentication unavailable" }, 503))),
),
);
};
2 changes: 2 additions & 0 deletions apps/cloud/src/env-augment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ declare global {
* the mirror current.
*/
WORKOS_WEBHOOK_SECRET?: string;
/** Temporary private routing bridge. Unset disables the endpoint. */
EXECUTOR_COEXISTENCE_KEY?: string;

// MCP
EXECUTOR_MCP_DEBUG?: string;
Expand Down
4 changes: 4 additions & 0 deletions apps/cloud/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import * as Sentry from "@sentry/cloudflare";
import handler from "@tanstack/react-start/server-entry";

import { coexistenceIdentity } from "./coexistence/identity";
import { isAppOwnedPath, servedByAppPlane } from "./app-paths";
import { marketingProxyRequest } from "./edge/marketing";
import { passthroughResponse } from "./edge/passthrough";
Expand Down Expand Up @@ -306,6 +307,9 @@ const prewarmAppPlane = (ctx: ExecutionContext): void => {

const cloudflareHandler = {
fetch: async (request, env, ctx) => {
if (new URL(request.url).pathname === "/__coexistence/identity") {
return coexistenceIdentity(request, env.EXECUTOR_COEXISTENCE_KEY);
}
isolateRequestSeq += 1;

// Public pages must not enter TanStack Start: its first-request dynamic
Expand Down
27 changes: 27 additions & 0 deletions notes/cloud-coexistence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Cloud coexistence identity endpoint

`GET /__coexistence/identity?kind=browser|mcp&organization=<id-or-slug>` is a
private bridge for the separate cloud coexistence router. It is disabled unless
`EXECUTOR_COEXISTENCE_KEY` is configured with at least 32 characters. The caller
must supply that key as `x-executor-coexistence-key`.

Browser requests validate the existing sealed WorkOS session and current org
membership. An omitted org uses the session's selected org. MCP requests use the
existing MCP credential validator and explicit organization selector; cookies do
not authenticate MCP requests. Existing WorkOS JWT and API-key behavior remains
owned by that validator.

The response contains only `userId`, `organizationId`, `organizationSlug` and
`role`. It never returns emails, cookies or credentials. Missing/wrong bridge
keys receive 404, invalid credentials 401, inaccessible orgs 403, and dependency
failures 503. All replies have `Cache-Control: no-store`.

This endpoint does not freeze or migrate data, change domains, or authorize a
cutover. No production deployment accompanies it. Configure the key only on the
intended backends and gateway; never in a browser bundle. The gateway must strip
private bridge headers from public traffic.

Verification: from `e2e`, run
`../node_modules/.bin/vitest run --project cloud cloud/coexistence-identity.test.ts`.
The scenario uses the real v1 Cloud runtime and WorkOS emulator, testing session
validation, cross-org denial, private-header protection and cookie-only MCP denial.
Loading