LegitFlash

Embed

LegitFlash embed

Run the verification inside your own site with a small script and an iframe. The applicant never leaves your page (except on phones, see below). Nothing about the applicant travels through the browser events: only event names, a step name or an error code. The result reaches you by webhook or API, as usual.

Quick start

  1. In the dashboard, open the flow and list Embed origins: the exact origins of the pages that will host the iframe (https://www.example.com, no path, no wildcard, https only, up to 10). A flow with no origins cannot be embedded.
  2. Create a session (API POST /sessions or the dashboard) and give the url to your page.
  3. Add the script and mount it:
Copied
<div id="trustid"></div>
<script src="https://YOUR-LEGITFLASH-DOMAIN/embed/v1/embed.js"
        integrity="sha384-HNjyNQ7Qo7hAYDcLlChRMLOwxo/4Y1scZIKTGk5uBCumX/2gQ6U1627VD5cDvCsa"
        crossorigin="anonymous"></script>
<script>
  TrustID.mount(document.getElementById('trustid'), {
    url: 'https://YOUR-LEGITFLASH-DOMAIN/v/SESSION-TOKEN', // the session's `url`
    mobile: 'redirect',                                 // optional, see "Phones"
    onEvent: (event) => console.log(event),
  });
</script>

mount returns { iframe, destroy() } (or null when it redirected a phone). The iframe is created with allow="camera", sandbox="allow-scripts allow-same-origin allow-forms" and referrerpolicy="no-referrer", and resizes itself to its content.

Subresource Integrity

Each version of the script has a fixed path and a fixed hash. Use the hash of the version you load:

Version Path SRI
v1 /embed/v1/embed.js sha384-HNjyNQ7Qo7hAYDcLlChRMLOwxo/4Y1scZIKTGk5uBCumX/2gQ6U1627VD5cDvCsa

A fix that keeps the same behaviour is released under the same path with a new hash (listed here and in the changelog); a breaking change gets a new path (/v2/) and v1 keeps working for 12 months. Recompute it yourself with openssl dgst -sha384 -binary embed.js | openssl base64 -A.

Events

onEvent receives { type, step?, code? }:

type When Extra
trustid:ready the frame loaded
trustid:step the applicant opened a step step: overview, id_front, id_back, selfie, liveness, poa
trustid:submitted the evidence was sent for review
trustid:closed the applicant pressed the close button
trustid:error a request failed code: a short code such as network, too_many, steps_incomplete

The script ignores any message that does not come from the LegitFlash origin and from that iframe. Do the same if you listen to message events yourself, and never trust an event for a business decision: wait for the signed webhook. The frame posts only to the parent origin it validated against the flow's list (the page's own origin, sent by embed.js, or the first listed origin as a fallback).

What your site must allow

  • Your CSP: frame-src https://YOUR-LEGITFLASH-DOMAIN and script-src https://YOUR-LEGITFLASH-DOMAIN (or the nonce of your own script tag). With SRI also keep crossorigin="anonymous" on the tag.
  • Camera: the iframe has allow="camera". If you create the iframe yourself, add it, and do not set a Permissions-Policy that blocks camera for the frame.
  • Framing: LegitFlash answers Content-Security-Policy: frame-ancestors <your origins> only for the embedded page. A page on an origin that is not in the list is blocked by the browser.
  • Cookies: none. The embed works with third-party cookies blocked. The applicant's browser keeps a device key in the frame's storage; if the browser blocks that storage, the session continues until the page reloads.

Phones

iOS needs HTTPS and a user gesture to start the camera, and many in-app browsers restrict camera access inside iframes. We recommend sending phones to the full-page flow: mobile: 'redirect' does it automatically (it navigates to the link without embed; set the flow's return URLs so the applicant comes back to your site). On desktop, the QR hand-off to a phone stays available inside the frame.

Try it locally

In the local environment open /dev/embed-test on one loopback host (http://localhost:8000) and paste a session link served from the other (http://127.0.0.1:8000/v/...). Add the first host to the flow's embed origins (plain http://localhost and http://127.0.0.1 origins are accepted in local only). Removing it must make the browser refuse the frame.

Rebuilding the script

npm run build:embed writes public/embed/v1/embed.js (committed). After changing resources/js/embed/embed.js, put the new hash in this file; a test fails otherwise.