TruthID
SDK Reference

TypeScript SDK

Full API reference for truthid-sdk on npm.

Full API reference for truthid-sdk on npm. New to TruthID? Start with the Quickstart — this page is the detailed reference for every method and type once you're integrating for real.

Installation

npm install truthid-sdk

Requires Node.js 16+.

TruthIDClient

import { TruthIDClient } from "truthid-sdk";

const truthid = new TruthIDClient({ network: "base-mainnet" });

Constructor

new TruthIDClient(config: TruthIDClientConfig)

FieldTypeRequiredDescription
network"base-sepolia" | "base-mainnet"Yes — no defaultWhich network to read contracts from
rpcUrlstringNoCustom RPC endpoint. Defaults to the public Base RPC for the chosen network

Unlike the Python and Ruby SDKs, network has no default here — you must pass it explicitly every time you construct a client.

Methods

createChallenge(origin)

Creates a one-time challenge to embed in the QR code shown to the user.

Parameters

NameTypeDescription
originstringYour site's domain, e.g. "yoursite.com"

Returns AuthChallenge

const challenge = truthid.createChallenge("yoursite.com");
// {
//   type: "challenge",
//   nonce: "3f2e1a4b-...",
//   issuedAt: 1718000000000,
//   origin: "yoursite.com"
// }

Store it, then delete it

Keep the challenge server-side, keyed by nonce, until verifyAuthResponse runs — then delete it immediately. See Nonce invalidation below.

Building the QR code — the 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 use https:// — the mobile app refuses to send the signed response to a plain http:// URL.


verifyAuthResponse(params)

Verifies the signed response received from the user's phone. Runs six checks in sequence and stops at the first failure:

  1. User approved (not rejected)
  2. Challenge is within TTL (default: 30 seconds)
  3. Nonce matches the original challenge
  4. Cryptographic signature is valid
  5. Device is registered and active on the blockchain
  6. Retrieves the identity ID linked to this device

Parameters (VerifyAuthParams)

NameTypeDescription
challengeAuthChallengeThe challenge you created
responseAuthResponseThe response received from the phone
ttlMs (optional)numberMax challenge age in ms. Default: 30_000

Returns VerifyAuthResult

const result = await truthid.verifyAuthResponse({ challenge, response });

if (result.valid) {
  console.log("Authenticated! Identity ID:", result.identityId);
} else {
  console.log("Failed:", result.reason);
}

Failure reasons

reasonCause
"User rejected the login request"User tapped "Reject" on their phone
"Challenge expired"More than ttlMs ms have passed since issuedAt
"Nonce mismatch"Response nonce doesn't match the challenge
"Invalid signature format"Signature is malformed
"Signature does not match device address"Signature was not made by deviceAddress
"Device is not active or has been revoked"Device was revoked by the identity owner

verifySession(sessionHash)

Checks whether a session hash is still valid (not revoked). Call this on subsequent requests after login to confirm the session hasn't been revoked from another device.

Parameters

NameTypeDescription
sessionHashstringbytes32 hex string (0x...)

Returns SessionInfo

const session = await truthid.verifySession(sessionHash);
if (session.exists && !session.revoked) {
  // still logged in
}

checkDeviceStatus(devicePubKey)

Looks up a device's current status on the blockchain.

Parameters

NameTypeDescription
devicePubKeystringEthereum address of the device (0x...)

Returns DeviceStatus

const status = await truthid.checkDeviceStatus(devicePubKey);

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 callbackUrl — there's no separate registration step for you to call.

If you want to double-check a session landed on-chain, derive its hash from the nonce and call verifySession:

import { keccak256, toBytes } from "viem";

const sessionHash = keccak256(toBytes(response.nonce));
const session = await truthid.verifySession(sessionHash);
if (session.exists && !session.revoked) {
  // confirmed on-chain
}

computeSmartAccountAddress(ledgerAddress, index?)

Predicts a user's smart account (controller) address via CREATE2 — pure local computation, no RPC call and no server involved. Useful for showing a deposit address, or checking a balance, before the account has ever been used on-chain.

Parameters

NameTypeDescription
ledgerAddress`0x${string}`The owning hardware wallet / EOA address
index (optional)bigintAccount index, for multiple smart accounts per owner. Default: 0n

Returns `0x${string}` — the checksummed smart account address.

const smartAccount = truthid.computeSmartAccountAddress(ledgerAddress);

A standalone function is also exported for when you don't need a full client instance:

import { computeSmartAccountAddress } from "truthid-sdk";

const smartAccount = computeSmartAccountAddress(ledgerAddress, "base-mainnet");

Types

All of the following are exported from truthid-sdk.

type Network = "base-sepolia" | "base-mainnet";

AuthChallenge

interface AuthChallenge {
  type: "challenge";
  nonce: string;
  issuedAt: number;   // Unix timestamp in ms
  origin: string;
}

AuthResponse

interface AuthResponse {
  approved: boolean;
  nonce: string;
  signature: string;          // secp256k1 signature, hex ("0x...")
  deviceAddress: string;      // Ethereum address of the device key
  sessionSignature?: string;  // personal_sign over keccak256(nonce) — always sent alongside signature
}

VerifyAuthParams

interface VerifyAuthParams {
  challenge: AuthChallenge;
  response: AuthResponse;
  ttlMs?: number; // default: 30_000
}

VerifyAuthResult

interface VerifyAuthResult {
  valid: boolean;
  identityId?: bigint;
  deviceAddress?: string;
  reason?: string;
}

SessionInfo

interface SessionInfo {
  exists: boolean;
  revoked: boolean;
  identityId?: bigint;
  devicePubKey?: string;
  createdAt?: Date;
}

DeviceStatus

interface DeviceStatus {
  exists: boolean;
  active: boolean;
  label?: string;
  identityId?: bigint;
  addedAt?: Date;
}

Security notes

Nonce invalidation

Delete the challenge from your store before calling verifyAuthResponse, not after — deleting after leaves a race condition where the same signed response can be submitted twice within the TTL window.

// Correct order
pendingChallenges.delete(response.nonce);             // delete first
const result = await truthid.verifyAuthResponse(...);  // then verify

TTL

The default is 30 seconds, matching the mobile app's own challenge expiry. Lowering it is fine; raising it above 30 seconds has no effect, since the phone will already refuse an older challenge.

HTTPS only

The phone POSTs the signed response directly to your callbackUrl — the mobile app refuses non-https:// URLs, and your endpoint still needs a valid TLS certificate for the connection to succeed.

Networks

NetworkChain IDDescription
"base-sepolia"84532Testnet — for development
"base-mainnet"8453Production
// Testnet during development
const truthid = new TruthIDClient({ network: "base-sepolia" });

// Custom RPC instead of the public endpoint
const truthid = new TruthIDClient({
  network: "base-mainnet",
  rpcUrl: "https://your-private-rpc.example.com",
});

Contract addresses for both networks are in Smart contracts.

Next steps

On this page