Manages client-side persistence of embed-surface proxy credentials (a platform API key + impersonation email) in `localStorage`, enabling embedded surfaces (chat widget, ticket center, etc.) to authenticate as a proxied customer across sessions. ## Key Components | Export | Type | Description | |--------|------|-------------| | `EmbedProxyAuth` | Interface | Shape of persisted credentials: `secret`, `email`, and optional identity fields (`firstName`, `lastName`, `avatarUrl`) | | `getEmbedProxyAuth()` | Function | Returns full normalized credentials or `null` (falls back to cookie auth) | | `getPersistedProxyEmail()` | Function | Returns only the last saved email, used to pre-fill the creds bar on mount | | `setEmbedProxyAuth()` | Function | Persists credentials with normalization; trims/lowercases email, strips whitespace-only optional fields | | `clearEmbedProxyAuth()` | Function | Removes credentials from `localStorage` | | `applyProxyAuth()` | Function | Attaches `Authorization: Bearer` + `X-Chat-Act-As` (and optional identity headers) to any fetch call | Storage key `.chat.proxy-auth.v1` is intentionally frozen — renaming it would silently log out all existing admin sessions. ## Usage Example ```typescript import { setEmbedProxyAuth, applyProxyAuth, clearEmbedProxyAuth } from './embed-proxy-auth-storage' // Save credentials (e.g. from the /debug creds bar) setEmbedProxyAuth({ secret: 'my-proxy-secret', email: 'customer@example.com', firstName: 'Jane', lastName: 'Doe', }) // Apply to a fetch call — no-op when no creds are stored const { url, headers } = applyProxyAuth('/api/chat/stream') const response = await fetch(url, { method: 'POST', headers }) // Admin logout / "Clear" button clearEmbedProxyAuth() ``` > **Security note:** Credentials persist in `localStorage` (survives tab close and browser restart). This is intentional — re-pasting on every tab was rejected as a dev-experience tradeoff. The `/debug` entry point is admin-gated, and all headers are server-validated against the hash-at-rest platform API key store (revocable in `/admin/api-keys`).