# Security

The merchant credentials are the merchant API key and, with the Identity
package, the RSA private key.

## Required controls

Apply these controls to each Digital ID integration:

1. Keep `X-API-Key` on the merchant backend.
2. Create sessions only from the merchant backend.
3. Validate `event.origin` for each `postMessage` event.
4. Accept events only from the configured widget origin.
5. Verify the JWT signature and the `aud`, `exp`, and `iss` claims.
6. Keep the RSA private key in the merchant backend secret manager.
7. Decrypt `my_identity` only after successful JWT verification.
8. Add `allow="camera"` to the iframe.
9. Register the merchant origin in the Privy allowlist.
10. Base business decisions only on the Privy-signed JWT after backend
    verification. This applies to a JWT from the exchange or the callback.

## Exchange code and session URL

The exchange code is single-use and has a short lifetime. It also requires the
merchant API key. It can travel through the front channel, but the merchant
must exchange it on the backend.

Treat `session_url` as sensitive. Do not log or expose the full URL.

## Embedder trust model

Privy sends data and tokens only to a verified iframe embedder. An unknown host
receives an event type without a payload.

A native WebView is a trusted host and receives the complete result payload.
The merchant must still process tokens and private identity data on the
backend.

> Do not make a business decision from front-channel data alone. The
> authoritative result is the Privy-signed JWT after the merchant backend
> verifies it. The exchange and the callback are two delivery channels for
> that result. Deduplicate processing by `session_id`.
