Wallet sign-in

No email, no password. You prove you own a wallet by signing one message (EIP-191 personal_sign).

The flow

  1. 1
    Ask for a message

    POST /v1/auth/nonce with your wallet address. You get a message containing a one-time nonce.

  2. 2
    Sign it

    Sign the message text with personal_sign. The wallet returns a 0x-prefixed 65-byte signature (130 hex characters), which you send as is.

  3. 3
    Exchange it

    POST /v1/auth/verify with the wallet and signature. You get a session token, valid for 24 hours.

text
Sign in to heura
Wallet: <your lowercase 0x address>
Chain: 4663
Nonce: <32 hex characters>
Expires: <ISO-8601 time, five minutes ahead>

Why it is safe

  • A nonce works once, even if the signature is wrong, and expires after five minutes. A captured signature cannot be replayed.
  • A signature from a different key is rejected. The app also refuses to sign any message that is not exactly these five lines for your address, on chain 4663, with an expiry still in the future.
  • The message is signed, never a transaction. Signing in cannot move funds.
  • Both endpoints are rate limited to 20 requests per minute per IP address.

Example

javascript
import nacl from "tweetnacl";

const base = process.env.HEURA_BRIDGE_URL;
const post = (p, b, h = {}) => fetch(base + p, { method: "POST", headers: { "content-type": "application/json", ...h }, body: JSON.stringify(b) }).then(r => r.json());

const { message } = await post("/v1/auth/nonce", { wallet });
const sig = nacl.sign.detached(new TextEncoder().encode(message), secretKey);
const { token } = await post("/v1/auth/verify", { wallet, signature: Buffer.from(sig).toString("base64") });
// use: Authorization: Bearer <token>