Code Reflector Infrastructure

9 min read

These pages are auto-generated from the monorepo docs.

Experimental Disclaimer

reflector is experimental software.

  • No SLA/SSLA: No service level agreements or support level agreements apply

  • No Support: No guaranteed support, response times, or issue resolution

  • Breaking Changes: APIs, configurations, and behavior may change without notice between versions

  • No Stability Guarantees: Features may be incomplete, modified, or removed at any time

  • Data Loss Risk: Bugs or changes may result in data loss or corruption

  • Use at Your Own Risk: This software is provided "as-is" without warranties of any kind

Experimental software is intended for evaluation and testing purposes only. Do not rely on this software for production workloads without understanding these limitations.

Maturity

Rated as experimental as of 2026.08.

Overview

Reflector renders dynamic HTML content generated by AI assistants. When an AI generates interactive content (charts, games, visualizations), the chat frontend stores the HTML in Reflector's in-memory store and retrieves it via a one-time-use nonce inside an iframe.

All data is in-memory only. Restarts clear the store. The nonce is an unguessable identifier and acts as the retrieval key. Because iframes can only load a URL — they cannot set request headers (like Authorization: Bearer ...) or a request body — retrieval additionally relies on an owner proof (UN-24154), presented one of two ways:

  • Owner-session cookie (same-site deployments): the authenticated upload sets a signed __Host-reflector_session cookie on the reflector origin, and the browser sends it on the iframe GET when chat and reflector share a registrable domain.

  • Fragment retrieval token (cross-site deployments, UN-27149): when chat and reflector are on different registrable domains the SameSite=Lax cookie is never sent on the iframe GET. The finalize response therefore also returns an entry-bound retrieval token which chat appends to the iframe URL as a #rt= fragment. Fragments never reach servers or logs; a small bootstrap page served in place of the content exchanges the token for a single-use 30-second nonce and re-navigates to ?once=<nonce>, which serves the content through the same code path and CSP as the cookie flow.

The store path is a chunked upload protocol: every individual HTTP request stays under the WAF's body inspection limit (default 64 KB per chunk). The frontend opens an upload session, streams chunks one at a time, and finalizes to receive the nonce. The legacy single-POST /html-store endpoint is still accepted for backward compatibility but is deprecated.

Architecture

embedded_ae50ca67038dc3831fd2f6cb43619d51.pngembedded_62a9db063d1a9a3e58ca9ec42541affe.png

The init and finalize responses set the __Host-reflector_session cookie (HttpOnly, Secure, SameSite=Lax) containing an HMAC-signed owner token. When chat and reflector share a registrable domain, the browser sends the cookie on the iframe's GET and the content is served directly. When they do not (e.g. tenant vanity domains, UN-27149), the GET instead returns the token-exchange bootstrap described above; a GET with neither a valid cookie nor a valid fragment token renders the same "not found or expired" message as an expired id — the bootstrap is served for unknown ids too, so responses leak no existence information. The retrieval token is HMAC-signed with the same keys, bound to a single entry id, and expires with the entry; because the rendered (untrusted) HTML can read its own fragment, the id-binding is what makes theft harmless — the token only grants re-reading the document that carries it. Its decodable payload is just {id, exp} — deliberately no owner key, so it also discloses nothing about the uploader to the rendered document (dedup is owner-scoped, so the entry id maps to exactly one owner and the signature alone proves ownership at mint time). Signing keys come from HTML_RENDERING_SIGNING_KEYS (JSON [{keyId, keyValue}], first key signs, all verify for rotation; keyId must not contain . — it is a field of the dotted token format); when unset, an ephemeral per-pod key is generated at startup. The ephemeral key is only sound with a single replica (the chart default pins replicaCount: 1): with multiple pods, a later upload landing on another pod overwrites the single __Host-reflector_session cookie with a token the first pod cannot verify, breaking retrieval of its still-live entries — and the retrieval nonce map is per-pod for the same reason. Configure shared signing keys before scaling out.

Chunked upload endpoints

Endpoint

Auth

Body

Purpose

POST /html-store/init

JWT (USER)

{ "totalBytes": <int> } (JSON)

Open an upload session. Returns { sessionId, chunkSize, expiresInMs }. The server-returned chunkSize is authoritative — clients must respect it so each chunk stays under the WAF body inspection limit.

POST /html-store/:sessionId/chunk

JWT (USER)

raw chunk bytes (application/octet-stream), X-Chunk-Index: <0-based int>, X-Chunk-Sha256: <hex> (optional but recommended)

Append a chunk. Chunks may arrive in any order. Re-POSTing the same (index, X-Chunk-Sha256) is idempotent and returns 204 without storing twice — safe to retry after a transient 502/503 from the WAF. Re-POSTing the same index with a different hash returns 409 Conflict.

POST /html-store/:sessionId/finalize

JWT (USER)

empty

Reassemble the chunks in index order, decode UTF-8, and store. Returns { id, retrievalToken } — the token is appended to the iframe URL as a #rt= fragment for cross-site retrieval (UN-27149). Idempotent for HTML_STORE_FINALIZED_TTL_MS: a retried finalize returns the same id (a fresh, equally valid retrievalToken is minted per response).

Sessions are owner-bound: the JWT identity that calls init is the only identity that can append chunks or finalize. Other authenticated users get 403 Forbidden.

Legacy single-shot endpoint (deprecated)

| POST /html-store | JWT (USER) | full HTML body (text/html) | Retained for backward compatibility while clients migrate. The body is read as a Node stream and capped by HTML_STORE_MAX_SIZE_BYTES. Tracked by the reflector_html_store_legacy_uploads_total counter so we can verify zero traffic before deletion. |

Security

Domain Isolation Required

Reflector MUST be hosted on a different subdomain than Unique Chat. The browser's same-origin policy treats different subdomains as different origins. A different top-level domain is not required — a distinct subdomain under the same domain is sufficient and avoids the overhead of managing separate domains and certificates.

✅ Correct: reflector.example.app and chat.example.app (different origin)

❌ Wrong: Both on chat.example.app (same origin — rendered HTML can access cookies)

The DNS A record for the reflector subdomain must point to the existing ingress gateway. This can be managed via external-dns, Terraform, or manual DNS provisioning.

Control

Description

Domain isolation

Reflector runs on a separate subdomain to prevent cookie access from rendered HTML

JWT on store

All POST /html-store/* endpoints require a valid Bearer token

Owner-bound sessions

Upload sessions are bound to the JWT identity that opened them; chunk and finalize from a different user return 403

Per-chunk size cap

Each chunk is limited to HTML_STORE_CHUNK_SIZE_BYTES (default 64 KB) to clear WAF body inspection limits

Total-size cap

Assembled total is capped at HTML_STORE_MAX_SIZE_BYTES (default 7 MB)

Nonce on retrieval

GET /scoped/html-store/:nonce requires the unguessable nonce in the URL path (see Overview for why JWT is not used here)

Owner-bound retrieval

Retrieval additionally requires an owner proof minted during the authenticated upload: the signed __Host-reflector_session cookie (same-site), or the entry-bound fragment retrieval token exchanged for a single-use 30s nonce (cross-site, UN-27149). No valid proof returns the bootstrap/404 with no existence leak (UN-24154). Content stays retrievable by its owner until TTL (no delete-on-read — iframe reloads and side-panel views re-fetch the same URL; cross-site reloads of a redeemed ?once= URL get the bootstrap again and re-exchange the retained #rt= fragment)

No nonce logging

The nonce is never written to server logs or the browser console — it is the retrieval capability (UN-24154 M7)

Referrer isolation

Retrieval responses carry Referrer-Policy: no-referrer and Cache-Control: no-store so the nonce cannot leak via Referer headers or caches

TTL expiration

Content expires after 60s (configurable)

Slot limits

Bounded in-memory slots prevent resource exhaustion (default: 50)

Session limits

Bounded concurrent in-flight upload sessions, default 200 (configurable via HTML_STORE_MAX_SESSIONS)

No persistence

All data is in-memory; restarts clear the store

Deployment

Reflector can be deployed with the backend-service Helm chart (version 10.2.0+, which supports route configuration). Container image: uniqueapp.azurecr.io/unique/reflector.

none
helm repo add unique https://unique-ag.github.io/helm-charts
helm install reflector unique/backend-service --version 10.2.0 -n chat -f reflector-values.yaml

Routes

The chart needs route config to expose two endpoints — one authenticated, one public. The scoped route only allows the /html-store path prefix with GET (preview retrieval) and POST (the cross-site token exchange POST /scoped/html-store/{id}/exchange, UN-27149). The hostname must be on a different subdomain than the chat frontend — see Security.

yaml
routes:
  hostname: reflector.<cluster-domain>
  pathPrefix: '/'
  paths:
    default:
      extraAnnotations:
        external-dns.alpha.kubernetes.io/enabled: 'true'
    probe:
      enabled: true
    scoped:
      enabled: true
      allowList:
        - # matches GET /scoped/html-store/{nonce} and POST /scoped/html-store/{id}/exchange
          path: /html-store
          type: prefix
          methods:
            - GET
            - POST
      extraAnnotations:
        external-dns.alpha.kubernetes.io/enabled: 'true'
        konghq.com/methods: GET,POST

Route

Path

Auth

Methods

Purpose

default

/

JWT required

POST

Store endpoint (POST /html-store)

scoped

/scoped/*

nonce in URL / retrieval token

GET, POST

Retrieval (GET /scoped/html-store/:nonce) and cross-site token exchange (POST …/:id/exchange)

Integration with Other Services

next-chat (frontend) — tells the browser where to reach Reflector:

Variable

Value

REFLECTOR_BACKEND_API_URL

https://reflector.<cluster-domain>

FEATURE_FLAG_DISABLE_HTML_DOWNLOAD_UN_25459

false

HTML download policy

FEATURE_FLAG_DISABLE_HTML_DOWNLOAD_UN_25459 is an off-by-default, company-scoped policy setting (not a rollout flag: it is meant to stay) that removes the HTML file download from every preview surface — the inline download menu, the "too large to display" fallback, the side panel, the code view's actions menu, and the compact file card used by the chat widget (where the file link otherwise downloads the artifact). It exists because a downloaded .html file, opened from disk, runs with none of the protections the in-app preview has. PDF and PNG export, copy-to-clipboard of the source and "Open in side panel" are unaffected.

Deployment Checklist

  • Deploy Reflector on a different subdomain than the chat frontend (not functionally required but security-critical)

  • Configure the ingress to route / (authenticated with JWT) and /scoped/* (GET and POST, protected by capability tokens not JWT) to Reflector. POST is required for the cross-site token exchange POST /scoped/html-store/:id/exchange (UN-27149) — a GET-only route breaks previews whenever chat and reflector are on different registrable domains

  • Ensure that both are cluster-external reachable addresses as the frontend can't use Kubernetes cluster-local routes (http://release-name.svc:port won't work)

  • Set REFLECTOR_BACKEND_API_URL in next-chat

  • Set HTML_RENDERING_SIGNING_KEYS (JSON [{keyId, keyValue}]) so owner cookies and retrieval tokens survive pod restarts and scale-out

  • Verify the reflector DNS A record points to the ingress gateway

  • Test: exercise the chunked upload sequence with a valid JWT — POST /html-store/init, POST /html-store/:sessionId/chunk, POST /html-store/:sessionId/finalize — and assert finalize returns { id, retrievalToken } and sets the __Host-reflector_session cookie

  • Test: GET /scoped/html-store/:id returns the HTML when the owner cookie is presented, and the token-exchange bootstrap page (HTTP 200, strict CSP) without it

  • Test: POST /scoped/html-store/x/exchange with Content-Type: text/plain and a garbage body returns a JSON 404 from the reflector with Access-Control-Allow-Origin: * — this proves the ingress forwards POST (a gateway-level 404/405 without those headers means the route is still GET-only)

Space Configuration

The Code Reflector is triggered when the Code Execution Tool creates an HTML file. Code Execution is by default activated in spaces that use OpenAI models on the Responses API. You can read more about how to configure Code Execution here.

Suggested prompt ideas / Tests

  • Snake — "Write me a quick snake game and render it as HTML"

  • Chart — "Write me a Plotly chart showing Microsoft stock with sample data"

  • Simulation — "Make a simulation of colliding particles"

Troubleshooting

HTML rendering does not trigger

Ensure that Code Execution is activated for the space. Code Execution is by default activated in spaces that use OpenAI models on the Responses API. See Code Execution for configuration details.

Content not loading in iframe

  • Verify the reflector hostname resolves and the A record points to the ingress gateway.

  • Check that the scoped route (/scoped/*) is reachable without authentication. Open https://reflector.<domain>/scoped/html-store/nonexistent in a browser — you should get the token-exchange bootstrap page (HTTP 200 with a strict Content-Security-Policy header), not a 401/403. The bootstrap is served for unknown ids too, so a 200 here does not mean the entry exists.

  • Check that the scoped route accepts POST: curl -i -X POST https://reflector.<domain>/scoped/html-store/x/exchange -H 'Content-Type: text/plain' --data 'v2.garbage' must return a JSON 404 from the reflector itself with Access-Control-Allow-Origin: *. A gateway-level 404/405 without those headers means the ingress is GET-only and cross-site previews will fail (UN-27149).

  • Both the store and retrieval URLs must be cluster-external. The frontend runs in the user's browser and cannot reach cluster-internal addresses.

Nonce expired or not found (404)

Content expires after 60 seconds by default. If the iframe loads slowly or the user's network is slow, the nonce may have expired before the iframe fetches it. The "not found or expired" message is also shown when the request carries no valid owner proof — neither the __Host-reflector_session cookie nor a valid #rt= fragment token — for example when the URL is opened in a different browser or by a different user than the uploader (this is intentional, see Security). Before UN-27149 (2026.40 + one release), deployments where chat and reflector sit on different registrable domains 404'd on every preview with reason=no_cookie; the fragment-token exchange now covers that topology with no extra configuration.

Last updated