diff --git a/packages/client/connection/src/browser-auth.ts b/packages/client/connection/src/browser-auth.ts index 5c8594df6f..e5f5fa9f44 100644 --- a/packages/client/connection/src/browser-auth.ts +++ b/packages/client/connection/src/browser-auth.ts @@ -198,12 +198,40 @@ async function initializeSecret(credentials: CredentialProvider): Promise PeerId, + ): void + /** Decide whether a trusted Host request has the required browser identity. */ + isAuthenticated(request: ConnectionTrustRequest, secure?: boolean): boolean + /** Resolve the peer identity of an authenticated API request, or undefined when it is not. */ + authenticateApi(request: ConnectionTrustRequest, secure?: boolean): PeerId | undefined +} + +/** Profile-selected policy that admits every request after the independent Host/Origin fence. */ +export const DISABLED_BROWSER_AUTHENTICATION: BrowserAuthentication = { + authenticatedUrl: baseUrl => new URL(baseUrl).href, + authorizeIndex: () => true, + authorizeConnect: () => undefined, + isAuthenticated: () => true, + authenticateApi: () => undefined, +} + /** * Process launch-token exchange and persistent signed-cookie verification. * Connection loads the credential provider's signing secret during activation * and retains it for synchronous request authentication. */ -export class BrowserAuth { +export class BrowserAuth implements BrowserAuthentication { private readonly launchToken: string private readonly maxAgeMilliseconds: number diff --git a/packages/client/connection/src/index.ts b/packages/client/connection/src/index.ts index d563cd40e8..0c0d2279f8 100644 --- a/packages/client/connection/src/index.ts +++ b/packages/client/connection/src/index.ts @@ -10,7 +10,7 @@ import { API_PATH } from './api-path.ts' import { CONNECT_PATH } from './connect-protocol.ts' import { bridge, DEFAULT_MAX_REQUEST_BODY_BYTES } from './http-bridge.ts' import { assertTrustedAuthority } from './api-request-trust.ts' -import { BrowserAuth } from './browser-auth.ts' +import { BrowserAuth, DISABLED_BROWSER_AUTHENTICATION } from './browser-auth.ts' import { HostConnectionService } from './rpc-host.ts' import { ConnectionRecoveryConfigSchema, resolveConnectionConfig, type ConnectionRecoveryConfig } from './recovery-config.ts' @@ -103,6 +103,8 @@ export interface ConnectionConfig { * an entry here. A non-canonical or non-bare authority fails plugin load. */ trustedHosts?: string[] + /** Host API browser identity policy; Host/Origin trust remains independent. Default: `required`. */ + browserAuthentication?: 'required' | 'disabled' /** Absolute browser and API cookie lifetime in days. Default: 30. */ cookieMaxAgeDays?: number /** Maximum buffered JSON body for every `/api` request. Default: 300 MiB. */ @@ -112,6 +114,7 @@ export interface ConnectionConfig { export const Config: z = z.object({ recovery: ConnectionRecoveryConfigSchema.default({}), trustedHosts: z.array(String).default([]), + browserAuthentication: z.union(['required', 'disabled']).default('required'), cookieMaxAgeDays: z.natural().min(1).default(30), maxRequestBodyBytes: z.natural().min(1).default(DEFAULT_MAX_REQUEST_BODY_BYTES), }) @@ -127,16 +130,21 @@ export async function apply(ctx: Context, config?: ConnectionConfig): Promise { assertImageBodyCapacity(webCtx, maxRequestBodyBytes) diff --git a/packages/client/connection/src/rpc-host.ts b/packages/client/connection/src/rpc-host.ts index 88e7b48baa..43a3feb74c 100644 --- a/packages/client/connection/src/rpc-host.ts +++ b/packages/client/connection/src/rpc-host.ts @@ -13,7 +13,7 @@ import { clientRequestSchema } from './rpc-schema.ts' import { bridge } from './http-bridge.ts' import { isRemoteAuthority, isTrustedApiRequest } from './api-request-trust.ts' import { API_PATH } from './api-path.ts' -import type { BrowserAuth } from './browser-auth.ts' +import type { BrowserAuthentication } from './browser-auth.ts' import { Peer } from './peer.ts' import type { PeerAdmission, @@ -82,12 +82,12 @@ export class HostConnectionService extends Service implements HostConnectionHand * Provide the Host half over the active HTTP server. * @param ctx - owning Connection plugin context. * @param trustedHosts - deployment authorities accepted by the Host/Origin fence. - * @param browserAuth - process token and persistent browser-session owner. + * @param browserAuth - profile-selected browser-session policy. */ constructor( ctx: Context, private readonly trustedHosts: readonly string[], - private readonly browserAuth: BrowserAuth, + private readonly browserAuth: BrowserAuthentication, ) { super(ctx, 'connection') this.owner = ctx