<iframe> on your page and receive KYC results and credential decisions directly in the parent window via an encrypted postMessage. No server-to-server webhook is required for the real-time channel.
This guide covers the client-side integration. The embeddable URL is created server-side when you create a request: you pass your iframe public key in the request body and Humanos returns a per-subject
link to embed.How It Works
- Your page generates an ECDH P-256 key pair using the Web Crypto API. The private key never leaves the browser.
- Your page sends the public key to your backend, which includes it in the
iframe.pubKeyfield of the create-request call. - Humanos returns a
linkfor each subject. You embed thatlinkin an<iframe>. - When the iframe loads, the backend detects the parent window’s origin and validates it against the allowlist configured in your dashboard. The origin is never taken from a query parameter; it is browser-detected and server-validated.
- After the user completes the flow, the iframe sends an encrypted
postMessageto your page. Your page decrypts it with the private key from step 1.
Unlike earlier versions of this integration, you do not append
pubKey or postMessageOrigin to the iframe URL. The public key is registered when the request is created, and the origin is detected automatically. The old query-parameter flow is no longer used.Prerequisites
- HTTPS: Both your page and the iframe must be served over HTTPS. The Web Crypto API is unavailable in insecure contexts, and trusted-session cookies require a secure context.
- Allowed origins: Your embedding origin must be registered in the Humanos Dashboard; see Dashboard Configuration. Up to 10 HTTPS origins can be configured, or
*to allow all, which is not recommended; see the warning below. - iframe notifications enabled: The embed/postMessage channel must be enabled for your organization, otherwise no encrypted payload is sent.
Step 1: Generate an ECDH Key Pair
Generate a P-256 key pair using the Web Crypto API. Mark the private key as non-extractable so it cannot be read by other scripts on the page.keyPair.privateKey reference. You will need it later to decrypt the payload.
Step 2: Create the Request with Your Public Key
SendpubKeyB64 to your backend, which creates the request with an iframe object. The public key goes in iframe.pubKey as base64-encoded P-256 SPKI; a request that includes iframe.pubKey is put into iframe mode.
In iframe mode,
The response is a secondaryContact is not supported, and the one-time code is sent lazily when the iframe first loads, not at request creation.GenerateRequestEntity whose subjects[] each carry a link, the URL to embed:
link is present for iframe / deferred-OTP requests. Pass it back to your page to embed.
Step 3: Embed the Link
Set the returnedlink as the src of your iframe. Do not add pubKey or postMessageOrigin query parameters; they are ignored.
The
allow attribute delegates the browser permissions the flow needs inside a cross-origin iframe:camerais required if the flow includes identity verification, since KYC needs camera access for the selfie and document scan steps.publickey-credentials-getlets a returning subject verify with a passkey (device biometrics) instead of typing the one-time code.publickey-credentials-createlets a subject save a passkey after confirming the code, so later approvals can use biometrics.
allow entries they do not recognize, so including all three is safe.Step 4: Listen for the Encrypted PostMessage
Register amessage event listener on the window. Always verify that event.origin matches the origin of the link you embedded, which is the Humanos app origin such as https://app.humanos.tech or https://app.humanos.id.
Step 5: Decrypt the Payload
The payload is encrypted using ECDH P-256 + HKDF-SHA256 + AES-256-GCM. The decryption derives a shared secret from the backend’s ephemeral public key and your private key, then uses HKDF to produce the AES key.Trusted Sessions: skip the OTP
For high-frequency approvals, where the same subject approves repeatedly for the same issuer, you can opt a request into a trusted browser session so the subject only completes the one-time code once. Subsequent approvals in the same browser skip the OTP automatically.Opting in
Setiframe.cookie when you create the request, as in Step 2:
How it works
- On the first approval, the subject completes the OTP as usual. On success, Humanos sets the
HttpOnly,Secure,SameSite=Nonecookiehumanos_trusted_sessionin the iframe, scoped to that subject + issuer and valid fordurationseconds. - Because the iframe is third-party, the browser must grant it cookie access via the Storage Access API. The Link app requests this on a user gesture; the user may see a one-time browser prompt.
- On subsequent approvals for the same subject + issuer, embedding the
linkauto-authenticates the session and the OTP step is skipped. If the cookie is missing, expired, revoked, or storage access is denied, the flow falls back to the normal OTP.
The trusted-session cookie is
HttpOnly, so it is never readable by your JavaScript, and it is never included in the postMessage payload. You only need to set iframe.cookie.allow; the Link app manages the cookie and the OTP-skip for you.Constraints
- Same browser, same subject, same issuer, within the configured
duration. - HTTPS only, since the cookie is
Secure, and the embedding origin must still pass the allowlist check; trusted sessions do not bypass origin validation. - If the browser blocks third-party storage and the user denies the Storage Access prompt, the subject completes the OTP normally.
Payload Structure
The decrypted plaintext is a JSON array of events, not a single object. Each event is shaped like a Humanos webhook event. A single completion typically contains oneidentity event and/or one credential event per credential decided.
The exact field names depend on the API version pinned to the API key that created the request. The shapes here are for
Every event shares these fields:
2026-07-06, the latest. A request created with an API key pinned to an older version receives the same events transformed to that version’s shape. For example, 2026-05-17 flattens decision.action/date to top-level action/decisionDate and returns user.did instead of user.id. Pin your API version and test against it.string
required
identity or credential.string
required
API version the payload is formatted for, as
YYYY-MM-DD.string
required
Identifier of the request.
string
required
Your organization’s DID.
object
required
The subject the event concerns.
eventType, each event adds its own fields:
Wire Format
The encrypted message posted viapostMessage is the outer envelope you receive on the message event. Decrypt its ciphertext to get the payload array above.
string
required
Envelope version, currently
1.boolean
required
Always
true; check it before processing the message.string
required
Encryption scheme:
ECDH-P256-AES-256-GCM.string
required
The backend’s ephemeral public key for the ECDH exchange, as base64 SPKI DER.
string
required
Initialization vector: a 12-byte nonce, base64-encoded.
string
required
AES-GCM ciphertext plus the 16-byte auth tag, base64-encoded.
Complete Example
A self-contained page that generates a key pair, asks your backend to create the request, passing the public key, embeds the returnedlink, listens for the encrypted message, and decrypts the array of events. Replace createHumanosRequest with a call to your own backend endpoint, which holds your API key and calls POST /request.
Security Considerations
- Origin validation: The backend validates the browser-detected parent origin against your configured allowlist. If the origin is not registered, and
*is not set, no encrypted payload is generated. The origin is never read from a query parameter. - Non-extractable private key: Generate the key with
extractable: falseso no script can read the raw key material. - Ephemeral keys: The backend generates a fresh ephemeral key pair for each payload, so compromising one message does not compromise others.
- Authenticated encryption: AES-256-GCM provides confidentiality and integrity. Tampered ciphertext fails decryption.
- Trusted-session cookies: The
humanos_trusted_sessioncookie isHttpOnly+Secure+SameSite=None, only the SHA-256 hash of the token is stored server-side, and it is strictly scoped to a single subject + issuer with a bounded lifetime. It does not bypass origin validation.
Dashboard Configuration
To enable the iframe postMessage channel:- Open your organization’s notification / embed settings in the Humanos Dashboard.
- Enable iframe notifications.
- Add your allowed origins: HTTPS only, up to 10.
You can set
When iframe notifications are disabled, the iframe will not send any * to allow all origins, but this disables clickjacking protection for the embed and is strongly discouraged in production. Prefer an explicit allowlist of your own HTTPS origins.postMessage events regardless of the request configuration.