Wallet sign-in
No email, no password. You prove you own a wallet by signing one message (EIP-191 personal_sign).
The flow
- 1Ask for a message
POST /v1/auth/noncewith your wallet address. You get a message containing a one-time nonce. - 2Sign 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. - 3Exchange it
POST /v1/auth/verifywith 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>