Skip to main content
When a mini app opens on a custom school page, Exode passes it initData — a string with user and school data signed with HMAC-SHA256 (similar to initData in Telegram Mini Apps). Once you verify the signature on your server, you can trust this data and authorize the user without your own registration.
Data from the postMessage context (ctx.user) is not signed and is suitable for display only. Any authorization on your backend must rely exclusively on verified initData.

How it works

  1. Exode opens your page in an iframe at https://your-domain/…#exodeInitData=<string>.
  2. The mini app reads the string from the fragment (retrieveInitData) and sends it to its backend.
  3. The backend verifies the signature with the page secret (verifyInitData) and gets the user data.
The page secret is issued in the school admin panel (School → Customization → Apps & pages, page menu ⋯ → Show secret) and is stored only on your server. Each page has its own secret.
retrieveInitData, useExodeInitData and verifyInitData are available in @exode-team/sdk starting from version 0.3.1.

In the mini app (browser)

retrieveInitData reads the fragment once, removes it from the address bar (so that the signed data does not leak when the link is copied) and caches the value. In React, use the useExodeInitData hook — it works the same way and does not require a provider. The user and session_uuid fields are present only for an authorized user. The set of fields may grow — when verifying the signature, include all fields except hash.

On your server (Node.js)

If the signature is invalid, the secret belongs to another page, or auth_date has expired, the function throws an exception (Error) — catch it and respond with 401.

Signature format

If you do not use Node.js, you can verify the signature manually in any language:
The initData string is encoded as application/x-www-form-urlencoded: when decoding, + means a space. Use your language’s standard query string parser rather than a manual split. The page secret is used as is — it is a string, and you do not need to decode it (hex/base64). After verifying the signature, compare auth_date (unix time in seconds) with the current time to discard stale data. Node.js example without the SDK:

Security recommendations

  • Limit the auth_date window (maxAgeSec) to 24 hours or less.
  • Serve the mini app pages with the header Content-Security-Policy: frame-ancestors https://<your-school-domain> — this ensures the app is embedded specifically in Exode.
  • Pass targetOrigin to the ExodeMiniApp constructor — the origin of the school page.
  • Never verify the signature in the browser: the secret must not leave your server.
  • If the secret is compromised, regenerate it in the admin panel (page menu ⋯ → Regenerate secret) — old initData will stop passing verification. Remember to update the secret on your server.

Updated: 2026-09-25 14:33 UTC