This repository has no description
flarebot docs owner-login-bridge.md
7.5 kB

Owner login and installation verification #

The customer sign-in link opens /auth/login. The existing PersonalAgent stores a ten-minute S256 challenge and a hash of an independent browser binding. The browser receives only a __Host-, Secure, HttpOnly, SameSite=Lax challenge cookie. Its top-level navigation to the configured control plane carries installation ID, state and the public PKCE challenge.

The control plane looks up the installation in the authenticated owner's registry. A verified installedRelease permits login, including during a failed update. Login uses the eight-hour control-plane identity; it does not require a selected account or an unexpired deployment grant. A fresh login starts ordinary Cloudflare OAuth with an encrypted, one-use continuation bound to the OAuth browser transaction. The continuation contains a fixed installation target, never a supplied return URL. The verified provider subject must own that installation before a code can be issued.

The one-minute code is hash-indexed in AuthVault and bound to the owner, installation, runtime origin, state and S256 challenge. A top-level GET returns to the registered runtime's /auth/callback, which atomically deletes its local challenge only when both cookie binding and state match. The runtime exchanges the code and verifier directly with /auth/bridge/exchange. This server exchange accepts no browser Origin, Cookie or Sec-Fetch-Site header. The control plane atomically consumes the code, rechecks ownership and returns an Ed25519 assertion. Redirects are handled manually and rejected; native Workers do not support Request.redirect: "error".

The runtime verifies the exact algorithm, key ID, issuer, audience, owner subject, installation, purpose, state, challenge, jti, issuance and expiry before issuing its existing eight-hour owner cookie. No caller can choose the resulting owner identity. Code, assertion and callback responses are no-store/no-referrer; successful callbacks immediately redirect to /. A failed or lost exchange requires a fresh login. A consumed code or challenge never reopens.

Deliberate configuration and key rotation #

FLAREBOT_CONTROL_PLANE.bridge and FLAREBOT_INSTALLATION.bridge contain {keyId, publicKey}, with the raw 32-byte Ed25519 public key encoded as unpadded base64url. FLAREBOT_BRIDGE_SIGNING_KEY is a control-plane-only Worker secret containing the PKCS8 private key in unpadded base64url. Signing verifies that the configured public pin matches the private key. It is never a customer binding, artifact module, renderer prop or browser value.

FLAREBOT_INSTALLATION.release contains {version, artifactDigest, operationId}. The publisher supplies the trusted artifact digest at deployment time, avoiding a self-referential bundle hash. Production installation requires both the bridge pin and release marker. Both additions remain optional for existing explicit development/runtime fixtures; missing configuration disables bridge routes.

This version accepts one exact key ID and public key. Preserve pins on unrelated installation retry. Rotation requires a deliberate deployment of the corresponding customer pins and coordinated publisher signing configuration; an unknown key fails closed, with no token-provided key or fallback trust. Existing customer cookies and encrypted model keys continue using the unchanged independent FLAREBOT_SESSION_SECRET. Changing the bridge pin never rotates that session secret.

Signed native health #

/auth/bootstrap-health accepts only a short CP assertion with the separate flarebot-bootstrap-health purpose. It binds the configured owner, installation, deployed release and operation marker, current origin, state and challenge. A login assertion cannot authorize health, and health cannot issue a customer session.

The runtime verifies native bindings, actual ASSETS delivery of the packaged /flarebot-health.txt marker, unauthenticated HTTP/WebSocket denial, and real PersonalAgent startup with its persisted owner/schema identity. PersonalAgent records the one-use health jti in its existing SQLite storage. It starts a fresh native Sandbox invocation containing only the fixed printf 'flarebot-native-health-v1' command, checks its exact output and zero exit status, and requires native teardown acknowledgement. No model inference, tool history, conversation, transcript or caller command is involved.

Health returns only identity, release/operation marker, challenge and readiness enums. It never returns stdout, keys, tokens, cookies or customer state. A completed probe is cached for one day by operation and artifact, so a lost response can be reconciled with a new signed assertion without another boot. The deployed operation marker may belong to the original upload intent after reauthorization; the orchestrator separately guards the current registry operation before accepting health. Pending probes persist until actual teardown; native parent restart retries their cleanup. Probe names are never reused because Sandbox invocation tombstones survive destroy.

Challenge and assertion tables prune expired entries and enforce 128-row caps. Completed health results expire after one day with a 32-row cap, and at most one probe may be pending. Atomic SQLite transactions protect local claims; encrypted native AuthVault transactions protect OAuth continuations and authorization codes. None of the added PersonalAgent methods is registered as browser-callable.

Protected deployment operation #

AuthVault stores encrypted {subject, accountId, installationId, operationId, grantRef, expiresAt, bootstrapSecret}. Native createOperation verifies the protected grant and rejects a deadline beyond that grant's validity. Creation/replay is atomic; replay must use the same binding, grant reference and deadline, and returns the original independently generated bootstrap secret. A different proposed secret never replaces it. Callers keep this result inside the trusted deployment callback, outside Workflow input/result/error records and installation metadata.

operation(expectedBinding) checks all four immutable binding fields and expiry. retireBootstrap(expectedBinding) removes bootstrap material while preserving the operation's protected grant reference. The alarm retires the entire encrypted record at expiry. If an ambiguous upload outlives this record, reconciliation must preserve an existing matching session-secret binding rather than generating a replacement.

Native acceptance gate #

Run node --test tests/bridge.test.mjs after the customer and control-plane builds. The test uses independent native Wrangler Workers and persisted SQLite DOs, a real local TLS proxy, Chromium on distinct publisher.test and *.workers.dev sites, and the exact pinned Sandbox image through Docker. The provider transport/admin routes are explicitly test-only fixtures. Production entries never export them.

The gate exercises fresh OAuth continuation, identity after grant expiry, wrong owner, exact assertion validation, actual owner-cookie HTTP/WebSocket access, denied browser RPC, changed PKCE/cookie/state/audience/installation, concurrent and expired claims, lost exchange, native restart retention, bounded tables, encrypted bootstrap replay and model-key persistence. Health verifies actual boot and destroy and reconciles a completed probe after restart. The local provider mapping does not certify live Cloudflare OAuth scopes, product permissions or Workers AI inference.