> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Browser encryption & UI Components

> Seal PANs and PII in the browser so plaintext never reaches your servers — collapsing your frontend PCI/PII scope. Client-side encryption, single-use reveal tokens, and iframe-isolated Card/Reveal components.

# Browser encryption & UI Components

Encrypt sensitive values **in the page**, against your tenant's public key, so plaintext (a card number, an SSN) never touches your servers. You store and transmit only a portable [`kc:` ciphertext](/essentials/encryption/ciphertext-spec) — and only KnoxCall, holding the private key, can decrypt it. No API key is ever shipped to the browser.

This is how you collapse a payment/PII frontend toward **PCI SAQ A**.

## 1. Client-side encryption (`@knoxcall/browser`)

Your backend fetches a **sealing bundle** (the tenant public key + a key reference — no private material) and hands it to the page. Encryption is then a pure client-side operation with no network round-trip.

```ts theme={"dark"}
// --- your backend (has the API key) ---
// GET /v1/encrypt/sealing-bundle?key=payments  ->  { public_key_raw, key_ref }
app.get('/checkout/sealing-bundle', async (req, res) => {
  const r = await fetch('https://api.knoxcall.com/v1/encrypt/sealing-bundle?key=payments', {
    headers: { Authorization: `Bearer ${process.env.KNOXCALL_API_KEY}` },
  });
  res.json(await r.json());
});
```

```ts theme={"dark"}
// --- the browser ---
import { KnoxEncryptor } from '@knoxcall/browser';

const bundle = await fetch('/checkout/sealing-bundle').then((r) => r.json());
const enc = new KnoxEncryptor(bundle, { purpose: 'pci' });

const ciphertext = await enc.encrypt(cardNumber); // "kc:1:s:…:$"
// send `ciphertext` to your backend / KnoxCall — the PAN never left the page.
```

The scheme (ephemeral ECDH P-256 → HKDF-SHA256 → AES-256-GCM) is byte-identical to the server, so any `kc:` value you produce here decrypts through `/v1/decrypt`, a [Relay route-action](/essentials/routes/what-are-routes), or a data-plane enclave.

## 2. Reveal to the browser without an API key

To show a user one decrypted value, your backend mints a **single-use, payload-pinned capability token** (see [client-side reveal](/essentials/encryption/overview#client-side-reveal-without-an-api-key)) and the page exchanges it once:

```ts theme={"dark"}
import { KnoxClient } from '@knoxcall/browser';

const knox = new KnoxClient();
const pan = await knox.reveal(capabilityToken, ciphertext);   // one-time
// or, for a vault token:
const value = await knox.detokenize(capabilityToken, 'tok_…');
```

The token is consumed server-side on first use, expires in minutes, and only matches the exact value it was minted for.

## 3. Iframe UI Components (`@knoxcall/react`)

For the strongest isolation, capture and display data inside a **cross-origin iframe** served from a KnoxCall origin. The host page — and any XSS on it — never sees the raw PAN; your callback receives only the `kc:` ciphertext plus non-sensitive display bits (last4/brand).

```tsx theme={"dark"}
import { CardCollect } from '@knoxcall/react';

<CardCollect
  bundle={bundle}
  purpose="pci"
  onChange={(complete) => setReady(complete)}
  onToken={(ciphertext, { last4, brand }) => {
    // store the ciphertext; show `•••• last4` to the user.
  }}
/>
```

Every message from the iframe is **origin-checked (exact match), source-checked (must be the KnoxCall iframe), and shape-validated** before your app trusts it — that logic lives in the shared, unit-tested protocol.

`<Reveal>` is the mirror: it decrypts (or detokenizes) with a capability token and displays the value *inside* the iframe, so plaintext is shown to the user but never crosses into your JavaScript.

## Which to use

| You need                                 | Use                                                                                                           |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Seal a value your own form already holds | `KnoxEncryptor.encrypt()`                                                                                     |
| Never let your JS touch the PAN at all   | `<CardCollect>` (iframe)                                                                                      |
| Show one decrypted value to a user       | capability token + `KnoxClient.reveal()` or `<Reveal>`                                                        |
| Decrypt server-side / in transit         | [`/v1/decrypt`](/essentials/encryption/overview) or [Relay route-actions](/essentials/routes/what-are-routes) |
