Documentation
Trancepad docs

Protocol, integration, and security for launches on Robinhood Chain.

Auth (SIWE)

Nonce, wallet signature, JWT Bearer token.

Protected API routes use a JWT from Sign-In with Ethereum. Get a nonce message, sign it with the wallet, then exchange signature + message for a token.

Steps

  1. POST /auth/nonce with { "wallet": "0x…" }.
  2. Sign the returned message with the wallet.
  3. POST /auth/login with wallet, signature, and message.
  4. Send Authorization: Bearer <token> on protected routes.
bashauth-curl.sh
WALLET=0xYourWallet

# 1) Nonce
curl -sS -X POST "${API_URL}/auth/nonce" \
  -H "content-type: application/json" \
  -d "{\"wallet\":\"$WALLET\"}"

# 2) Sign the returned message in your wallet, then:
curl -sS -X POST "${API_URL}/auth/login" \
  -H "content-type: application/json" \
  -d "{\"wallet\":\"$WALLET\",\"signature\":\"0x…\",\"message\":\"<exact message>\"}"

# 3) Authenticated call
curl -sS "${API_URL}/auth/me" -H "authorization: Bearer $JWT"
tssiweLogin.ts
import { createWalletClient, custom } from "viem";

const API = process.env.API_URL!; // e.g. https://api.example.com

async function login(address: `0x${string}`) {
  const nonceRes = await fetch(`${API}/auth/nonce`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ wallet: address }),
  }).then((r) => r.json());
  if (!nonceRes.success) throw new Error(nonceRes.error);

  const { message } = nonceRes.data as { nonce: string; message: string };
  const wallet = createWalletClient({ transport: custom(window.ethereum) });
  const signature = await wallet.signMessage({ account: address, message });

  const loginRes = await fetch(`${API}/auth/login`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ wallet: address, signature, message }),
  }).then((r) => r.json());
  if (!loginRes.success) throw new Error(loginRes.error);

  return loginRes.data.token as string; // Authorization: Bearer …
}

Troubleshooting

  • Message must match exactly (including domain configured as SIWE_DOMAIN).
  • Wallet in login must match the signer.
  • 401 on protected routes: refresh JWT via login again.