mMoney Docs

Mini apps

Verify the launch token

The launch token is a 60-second HS256 JWT. mMoney signs it with your mini app’s launch-token secret. Your frontend forwards it to your backend. Your backend verifies it before it trusts the user.

Claims

Claim Type Meaning
iss string Always bitt.com.
aud string Your mini-app slug. Verify this matches you.
sub string The pseudonymous user ID. Use it as your user reference.
mini_app_id integer The numeric mini-app ID.
nonce string One-shot nonce.
iat / exp integer Issued-at and expiry (unix seconds).

Always verify four things:

  1. The algorithm is HS256. Reject none and RS-prefixed algorithms.
  2. The issuer is bitt.com.
  3. The audience is exactly your slug.
  4. The token is not expired. A standard JWT library enforces this.

Node.js

import jwt from "jsonwebtoken";

const claims = jwt.verify(launchToken, MINI_APP_JWT_SECRET, {
  algorithms: ["HS256"],
  issuer: "bitt.com",
  audience: "your-mini-app-slug"
});

Python

import jwt  # PyJWT

claims = jwt.decode(
    launch_token,
    MINI_APP_JWT_SECRET,
    algorithms=["HS256"],
    issuer="bitt.com",
    audience="your-mini-app-slug",
)

PHP (firebase/php-jwt)

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$claims = JWT::decode($launchToken, new Key($MINI_APP_JWT_SECRET, 'HS256'));

if ($claims->iss !== 'bitt.com')           throw new Exception('bad iss');
if ($claims->aud !== 'your-mini-app-slug') throw new Exception('bad aud');

Elixir (Joken)

signer = Joken.Signer.create("HS256", mini_app_jwt_secret)
config = Joken.Config.default_claims(iss: "bitt.com")

case Joken.verify_and_validate(config, token, signer) do
  {:ok, %{"aud" => "your-mini-app-slug"} = claims} -> {:ok, claims}
  _ -> {:error, :invalid}
end

Rotation

Rotation invalidates old tokens immediately. There is no overlap window. Deploy the new secret to all backend instances before you rotate in the dashboard.