Embedded SDK (web message)

Truora Pass provides a lightweight JavaScript SDK, TruoraPass, that runs the authorization flow inside a modal on your own page instead of redirecting the user’s browser away from your application. Truora Pass opens in an embedded iframe and delivers the authorization code back to your page through a browser postMessage event, using response_mode=web_message.

The result is the same as the Authorization Code flow: your application receives an authorization code, and your backend exchanges it for tokens. Only the front-channel changes — there is no full-page redirect.

Registration requirements

The embedded flow must be enabled for your application before you can use it. You enable it yourself in the Truora Pass Dashboard, when creating or editing your application:

  • Enable JavaScript Client (allows_web_message): turn the toggle on.
  • Authorized JavaScript origins (allowed_web_message_origins): the list of web origins allowed to embed Truora Pass (origin only — scheme + host, no path). The origin of the redirectUri you pass to the SDK must be in this list, or the authorization is rejected.

See Registering your application for the dashboard walkthrough and the full list of configurable fields.

1. Load the SDK

Load client.js from the Truora Pass host with a script tag:

<script src="https://pass.truora.com/client.js"></script>

The script exposes a global TruoraPass object.

2. Initialize with TruoraPass.init

Call TruoraPass.init once, before any authorization attempt:

TruoraPass.init({
  appClientId: "WLT_APP_your_client_id",
  onAuthorized: function (result) { /* { code, state } */ },
  onCancelled: function (result) { /* { state } */ },
  onError: function (result) { /* { error, error_description, state } */ },
  onClose: function () { /* modal closed */ }
});
Option Required Description
appClientId Yes Your application’s client_id (WLT_APP_...). init throws if it is missing.
baseUrl No The Truora Pass host. Defaults to production (https://pass.truora.com).
onAuthorized No Called with {code, state} when the user completes authorization.
onCancelled No Called with {state} when the user cancels.
onError No Called with {error, error_description, state} when authorization fails.
onClose No Called when the modal is closed.

Note: baseUrl can simply be omitted — it defaults to https://pass.truora.com, the same host you load client.js from.

3. Start the flow with TruoraPass.authorize

TruoraPass.authorize({
  redirectUri: "https://app.example.com/callback",
  scope: "openid profile email",
  state: "<unguessable random value>"
});
Parameter Description
redirectUri A registered redirect URI. Its origin must be in allowed_web_message_origins.
scope Space-delimited scopes to request. See the Scopes reference.
state An opaque random value your page generates. Echoed back in every callback — verify it matches.

TruoraPass.authorize returns nothing (void). The outcome is delivered exclusively through the init callbacks. It throws if TruoraPass.init was not called first.

Under the hood, the SDK opens the Truora Pass /authorize page in an iframe with response_type=code and response_mode=web_message, passing your client_id, scope, state, and redirect_uri.

4. Receive the result

Truora Pass posts the result to your page as a message. The SDK verifies that the message comes from the Truora Pass origin and from its own iframe, invokes the matching callback exactly once, and then closes the modal automatically:

Event Callback Payload
wallet:authorized onAuthorized { code, state }
wallet:cancelled onCancelled { state }
wallet:error onError { error, error_description, state }

5. Exchange the code server-side

The code in the wallet:authorized payload is an authorization code — it is not a token. Send it to your backend and exchange it there, exactly as in the redirect flow: POST https://api.pass.truora.com/v1/oauth2/token with your client_secret. Never exchange the code in the browser: the exchange requires your client_secret, which must never be exposed in frontend code.

The exchange request, response, and error handling are identical to the Authorization Code flow — including that the code is single-use and short-lived.

  • On desktop, Truora Pass opens as a centered 440×680 modal over a fixed page overlay.
  • On viewports 640px wide or narrower, it opens as a bottom sheet covering 90% of the viewport height.
  • The embedded iframe is allowed to use the camera and WebAuthn, so the user can complete document capture, face verification, and passkey sign-in without leaving your page.
  • Once a callback fires, the modal closes automatically.

Complete example

A minimal page that signs a user in with Truora Pass and forwards the code to its own backend:

<button id="truora-pass-signin">Sign in with Truora Pass</button>

<script src="https://pass.truora.com/client.js"></script>
<script>
  // Generate an unguessable state and keep it to verify the response
  const state = crypto.randomUUID();

  TruoraPass.init({
    appClientId: "WLT_APP_your_client_id",

    onAuthorized: function (result) {
      if (result.state !== state) {
        console.error("state mismatch — discarding response");
        return;
      }

      // Exchange the code on YOUR server (never in the browser)
      fetch("/truora-pass/callback", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ code: result.code })
      });
    },

    onCancelled: function (result) {
      console.log("user cancelled authorization", result.state);
    },

    onError: function (result) {
      console.error("authorization failed:", result.error, result.error_description);
    },

    onClose: function () {
      console.log("Truora Pass modal closed");
    }
  });

  document.getElementById("truora-pass-signin").addEventListener("click", function () {
    TruoraPass.authorize({
      redirectUri: "https://app.example.com/callback",
      scope: "openid profile email",
      state: state
    });
  });
</script>

Your backend endpoint (/truora-pass/callback above) performs the token exchange and then reads the user’s identity from /v1/oauth2/userinfo — see UserInfo and claims.

Note: The example generates state in the browser for brevity. For high-risk applications, follow the same practice as the Authorization Code flow: generate state on your server, bind it to the user’s session, and verify it server-side when the code arrives — a browser-only check does not protect a compromised page.