Authentication Flow
DeroAuth uses a challenge-response pattern similar to SIWE (Sign-In With Ethereum), adapted for DERO's Schnorr signature scheme.
Flow Diagram
User Browser Server
| | |
| Click "Sign In" | |
|------------------------>| |
| | POST /auth/challenge |
| | { address } |
| |------------------------>|
| | { messageText, nonce } |
| |<------------------------|
| | |
| Wallet: "Sign this?" | XSWD: SignData(message) |
| [Approve] [Deny] | |
|------------------------>| |
| PEM signature | |
| | POST /auth/verify |
| | { signature, nonce } |
| |------------------------>|
| | Verify Schnorr sig |
| | Check domain/nonce |
| | { session (JWT) } |
| |<------------------------|
| Authenticated! | |Step by Step
1. Challenge Generation
The server creates a human-readable message for the user to sign:
myapp.com wants you to sign in with your DERO wallet:
dero1qy...abc123
Sign in to My App
URI: https://myapp.com
Version: 1
Chain ID: dero-mainnet
Nonce: k8j2m4n6p8q0
Issued At: 2026-02-14T12:00:00.000Z
Expiration Time: 2026-02-14T12:05:00.000ZKey properties:
- Domain-bound — Prevents phishing (the domain is displayed in the wallet)
- Nonce — Crypto-random, single-use, prevents replay attacks
- Expiry — Short window (default 5 minutes) limits exposure
- Human-readable — Users can verify what they're signing
2. Wallet Signing (XSWD)
The browser connects to the user's local DERO wallet via the XSWD protocol (WebSocket):
- Engram desktop wallet:
ws://localhost:44326 - DERO CLI wallet:
ws://localhost:10103
The XSWD client sends a SignData request with the challenge message. The wallet displays the message and asks the user to approve or deny.
If approved, the wallet returns a PEM-encoded Schnorr signature.
3. Server Verification
The server verifies the signature without needing a DERO node:
- Parse the PEM signature format
- Decode the DERO address to extract the BN256 public key
- Hash the message with Keccak-256, reduced modulo the curve order
- Verify the Schnorr signature against the public key
- Check domain, nonce, and expiry
- Consume the nonce (prevents replay)
- Issue a JWT session token
The entire verification is mathematical — it uses @noble/curves to verify the Schnorr signature on the BN256 curve. No RPC call to a DERO node is needed. This means your auth server doesn't need to run a DERO daemon.
4. Session
A standard JWT is issued containing the DERO address. Use it like any other session token:
// Server: verify the session
import { createSessionManager } from "dero-auth/server";
const sessions = createSessionManager({ secret: process.env.JWT_SECRET! });
const payload = await sessions.verify(token);
// { address: "dero1qy...", iat: ..., exp: ... }Replay Protection
Nonces are single-use and stored server-side:
- Development: In-memory store (default)
- Production: Redis store with atomic consume (recommended for multi-instance)
A nonce can only be used once — if an attacker captures a signed message, they can't replay it.