TruthID

Quickstart

Add Login with TruthID to your backend: create a challenge, show a QR code, and verify the signed response.

Add "Login with TruthID" to your backend: create a challenge, show it as a QR code, and verify the signed response that comes back from the user's phone. Check the prerequisites first — you'll need a backend that can receive an HTTPS POST.

1. Install the SDK

npm install truthid-sdk

2. Create a challenge

A challenge is what gets embedded in the QR code on your login page. It's single-use and expires after 30 seconds — create it on demand, right before rendering the QR code.

import { TruthIDClient } from "truthid-sdk";

const truthid = new TruthIDClient({ network: "base-mainnet" });
const pendingChallenges = new Map(); // any store with a TTL works

app.get("/auth/challenge", (req, res) => {
  const challenge = truthid.createChallenge(req.hostname);
  pendingChallenges.set(challenge.nonce, challenge);

  res.json({
    action: "truthid-auth",
    challenge,
    callbackUrl: `https://${req.hostname}/auth/verify`,
  });
});

3. Render the QR code

Your frontend turns that JSON response into a QR code — any QR rendering library works, server-side or client-side. The TruthID mobile app expects this exact shape:

{
  "action": "truthid-auth",
  "challenge": { "type": "challenge", "nonce": "...", "issuedAt": 1718000000000, "origin": "yoursite.com" },
  "callbackUrl": "https://yoursite.com/auth/verify"
}

callbackUrl must be https:// — the mobile app refuses to send the signed response anywhere else.

4. Verify the response

When the user approves on their phone, it POSTs straight to callbackUrl — no server in between. verifyAuthResponse checks the signature and reads the device's status from the blockchain.

app.post("/auth/verify", async (req, res) => {
  const response = req.body;
  const challenge = pendingChallenges.get(response.nonce);
  if (!challenge) return res.status(400).json({ error: "Challenge not found or already used" });
  pendingChallenges.delete(response.nonce); // prevents replay

  const result = await truthid.verifyAuthResponse({ challenge, response });
  if (!result.valid) return res.status(401).json({ error: result.reason });

  res.json({ identityId: result.identityId!.toString() });
});

That's the whole backend integration. Full runnable examples (Express, Flask, Sinatra) with session tokens and a protected route are in the SDK reference.

Session visibility — nothing to do

Completed logins already show up in the user's TruthID mobile/desktop apps and can be individually revoked from there. The phone registers the session on-chain itself (via a UserOperation) before it ever calls your /auth/verify endpoint — there's no relayer to fund and no separate registration step. See the SDK reference (TypeScript, Python, Ruby) if you want to double-check a session landed on-chain via verifySession.

5. Test it with a real device

To actually scan a QR code and approve a login, you need:

  • A TruthID identity — created once with any EVM wallet on Base.
  • A trusted device paired to that identity — the desktop app or the mobile app.

Download the desktop app and the browser extension from the TruthID landing page — pre-built installers for Linux, Windows, macOS (Apple Silicon), and an Android APK.

Two things that trip people up on the first try:

  • callbackUrl must be reachable from the internet over HTTPS — localhost won't work. Use a tunnel (e.g. ngrok http 3000) during development.
  • The challenge expires in 30 seconds, so generate it right before showing the QR code, not ahead of time.

Next steps

On this page