import { MastraAuthWorkos } from '@mastra/auth-workos'; import type { ApiRoute, IMastraAuthProvider } from '@mastra/core/server'; import type { Context, Hono } from 'hono'; import type { RouteAuth } from './routes/route.js'; /** * Provider-neutral factory auth gating for the MastraCode web server. * * When an auth provider is active (a `MastraAuthProvider` instance passed to * `MastraFactory`'s `auth` slot, or — back-compat for suites/paths that never * boot the factory — implied by the WorkOS env vars), every route on the web * server is placed behind it: unauthenticated browser navigations are * redirected to the SPA's `/signin` page, API/XHR calls receive a 401, and a * small set of public routes stay reachable while signed out — the provider's * `/auth/*` routes plus `/auth/me`, the `/signin` page, its `/assets/*` bundle, * and the SPA manifest metadata. When no provider is active, `mountFactoryAuth` is a no-op and the server * behaves exactly as it does without auth. * * Provider specifics stay in the providers (`@mastra/auth-workos`, * `@mastra/auth-better-auth`, or any custom `IMastraAuthProvider`); this * module composes them capability-first via the core type guards: * - `authenticateToken` — session/bearer validation (all providers) * - `ISSOProvider` — hosted-login `/auth/login`, `/auth/callback`, `/auth/logout` * - `IAuthHttpHandler` — provider-owned `/auth/api/*` endpoints (better-auth) * - `IOrganizationsProvider` — personal-org bootstrap + admin checks * - `ICredentialsProvider.isSignUpEnabled` — SPA sign-up affordance * - `getClearSessionHeaders` — session cookie clearing on logout */ /** Minimal shape of the signed-in user surfaced to the SPA (no tokens). */ export interface FactoryAuthUser { /** Stable WorkOS user id used to scope per-user data (GitHub installs etc.). */ workosId?: string; /** Provider user id; WorkOS shapes may use `workosId` instead (see {@link workosId}). */ id?: string; email?: string; name?: string; /** Provider-supplied profile picture URL, when the auth provider exposes one. */ avatarUrl?: string; /** * Organization id. The org is the top-level tenant: it owns the GitHub * App installation and connected projects, while each user inside the org gets * isolated building instances. Absent for personal (no-org) accounts. */ organizationId?: string; /** Organization ids proven by the provider's authenticated membership response. */ organizationMembershipIds?: string[]; } /** * Tenant identity: the org is the top-level tenant, and each user inside it is * an isolated builder. Agent state, worktrees and sandboxes are scoped per * `(orgId, userId)`. Personal (no-org) users have `orgId === undefined`. */ export interface FactoryAuthTenant { /** Organization id, or `undefined` for personal (no-org) accounts. */ orgId?: string; /** Stable provider user id. */ userId: string; } /** * Validate that a `returnTo` value is a safe same-site path, to prevent * open-redirect attacks. Only absolute local paths (`/foo`) are allowed; * protocol-relative (`//evil.com`) and absolute URLs are rejected. */ export declare function sanitizeReturnTo(raw: string | undefined): string; /** Extract a bearer token from the Authorization header, if present. */ export declare function getBearerToken(authorization: string | undefined): string; /** * Whether the SPA is served cross-origin from this API (platform deploy). When * `MASTRACODE_ALLOWED_ORIGINS` is set the browser talks to us cross-site, so * session cookies must be `SameSite=None; Secure` for the browser to send them. * Same-origin local dev leaves this unset and keeps the stricter `SameSite=Lax`. */ export declare function isCrossSiteAuth(): boolean; /** Hono context variables set by the auth gate. */ export interface FactoryAuthVariables { factoryAuthUser: FactoryAuthUser; } /** * Read the authenticated user the gate stashed on the context, or * `undefined` when unauthenticated / auth disabled. Used by downstream routes * (e.g. GitHub) to scope rows per user. */ export declare function getFactoryAuthUser(c: Context): FactoryAuthUser | undefined; /** * Read the authenticated user off a request context, normalizing whatever the * active auth provider put there. * * The server's auth layer writes the provider's `authenticateToken` result into * the request context's `user` slot verbatim, so the value's shape follows the * provider: WorkOS writes a flat user, better-auth writes a `{ session, user }` * wrapper whose org lives on the session. Reading that slot as a * {@link FactoryAuthUser} therefore yields `undefined` for both the id and the * org under better-auth, which reads as "this session belongs to somebody else" * at every ownership check. Normalize on the way in instead. */ export declare function getFactoryAuthUserFromContext(requestContext: { get: (key: string) => unknown; } | undefined): FactoryAuthUser | undefined; /** Resolve the stable user id from an authenticated user shape. */ export declare function getFactoryAuthUserId(user: FactoryAuthUser | undefined): string | undefined; /** Resolve the organization id from a user shape, if present. */ export declare function getFactoryAuthOrgId(user: FactoryAuthUser | undefined): string | undefined; /** * Resolve the tenant identity `(orgId, userId)` from the authenticated user on * the context. Returns `undefined` when there is no signed-in user (auth * disabled or unauthenticated). `orgId` is `undefined` for personal accounts; * callers gate org-scoped GitHub features on its presence while agent state * falls back to a user-only tenant. */ export declare function factoryAuthTenant(c: Context): FactoryAuthTenant | undefined; /** * Fail-closed authorization for organization-level administrative mutations. * The caller must belong to the same active organization and the provider must * explicitly confirm an admin/owner role. */ export declare function isOrganizationAdmin(provider: IMastraAuthProvider | undefined, c: Context, organizationId: string): Promise; /** * Build the factory's implementation of the `RouteAuth` seam over the * resolved provider (`undefined` = auth disabled). Constructed once per boot * by `MastraFactory.prepare()` and handed to factory route modules at * construction — they never import the factory auth module directly. */ export declare function createFactoryRouteAuth(provider: IMastraAuthProvider | undefined): RouteAuth; /** True when the given provider is WorkOS. Gates WorkOS-only capabilities. */ export declare function isWorkOSAuth(provider: IMastraAuthProvider | undefined): boolean; /** * The raw WorkOS provider, for features that need the WorkOS client directly * (audit-log export, Admin Portal links). Callers must gate on * {@link isWorkOSAuth} first — throws when the provider is not WorkOS. */ export declare function getWorkOSProvider(provider: IMastraAuthProvider | undefined): MastraAuthWorkos; /** * Resolve the authenticated user for a request, stashing it on the context. * * The gate only authenticates non-`/auth/*` requests via the `Authorization` * header, so cookie-based browser navigations to public `/auth/*` routes (the * GitHub connect/callback flow) arrive without a gate-stashed user. This reads * the session cookie from the raw request the same way `/auth/me` does, * caches the result on the context, and returns it so downstream helpers like * {@link factoryAuthTenant} work uniformly on both gated and public routes. * * Returns `undefined` when there is no valid session (or auth is disabled). */ export declare function ensureFactoryAuthUser(provider: IMastraAuthProvider | undefined, c: Context): Promise; export interface MountFactoryAuthOptions { /** * Explicit auth provider to mount. When omitted, falls back to a WorkOS * provider implied by the `WORKOS_*` env vars (back-compat for suites that * never boot the factory). */ provider?: IMastraAuthProvider; /** * Absolute URL the identity provider redirects back to after login (WorkOS * env-fallback path only). Defaults to the `WORKOS_REDIRECT_URI` env var. */ redirectUri?: string; /** Browser-facing origin used to derive the SSO callback URL. */ publicUrl?: string; } /** * Register the public `/auth/*` routes on a Hono app: the capability-derived * provider routes (login/callback/logout/provider APIs) plus the * provider-neutral `/auth/me`. Split out from `mountFactoryAuth` so both the local * Hono server and the platform Mastra entry can reuse the exact same handlers. */ export declare function registerAuthRoutes(app: Hono, provider: IMastraAuthProvider, options?: { publicUrl?: string; }): void; /** * Build the public `/auth/*` routes (provider routes + `/auth/me`) as Mastra * `server.apiRoutes`. Used by the platform Mastra entry (`src/mastra/index.ts`), * which can't register plain Hono routes on the deployer-generated app the way * the local server does via {@link registerAuthRoutes}. * * Handlers are identical to {@link registerAuthRoutes}. All are `requiresAuth: false` * (they must be reachable while unauthenticated), and the gate middleware skips * `/auth/*` so it never blocks them. `/auth/*` is not under `/api`, so it is a * valid custom-route path. */ export declare function buildAuthRoutes(provider: IMastraAuthProvider, options?: { publicUrl?: string; }): ApiRoute[]; /** * Build the auth gate as a plain Hono middleware handler `(c, next)`. Protects * everything that is not a public `/auth/*` route: authenticated requests stash * the user on the context and continue; unauthenticated navigations redirect to * login and XHR/API calls get a 401 JSON. Shared by the local Hono server * (`mountFactoryAuth`) and the platform Mastra entry (`server.middleware`). */ export declare function createFactoryAuthGate(provider: IMastraAuthProvider): (c: Context, next: () => Promise) => Promise; /** * Mount factory auth gating onto the host app. No-op when auth is disabled * (no provider active). * * Must be called before the Mastra adapter routes, the `/web/*` routes, and * the static UI handlers so the gate covers every request. Composes the shared * `registerAuthRoutes` + `createFactoryAuthGate` factories so the local Hono server * and the platform Mastra entry stay behavior-identical. */ export declare function mountFactoryAuth(app: Hono, options?: MountFactoryAuthOptions): boolean; //# sourceMappingURL=auth.d.ts.map