dero-auth
v0.2.1
Published
Wallet-based authentication for DERO — Sign in with your DERO wallet. No email, no password, just cryptographic proof.
Maintainers
Readme
dero-auth
Sign in with your DERO wallet. No email. No password. Just cryptographic proof of wallet ownership.
dero-auth is a TypeScript library that provides wallet-based authentication for DERO — a privacy-focused cryptocurrency with encrypted transactions. It works like "Sign in with Ethereum" (SIWE/EIP-4361), but for DERO's privacy chain.
Privacy advantage: Unlike Ethereum auth, authenticating with DERO doesn't expose your transaction history. Your on-chain activity remains invisible to the service.
Features
- Pure TypeScript signature verification (Schnorr on BN256) — no wallet needed server-side
- React components — drop-in
<SignInWithDero />button anduseDeroAuth()hook - Next.js integration — ready-made API route handlers and auth middleware
- XSWD client — connects to DERO wallets (Engram, CLI) via WebSocket
- SIWE-style message format — human-readable, domain-bound, replay-protected
- JWT sessions — standard token-based session management
- Zero personal data — just a cryptographic address
Quick Start
Install
npm install dero-authSet a JWT Secret (required)
Use a strong secret (at least 32 bytes):
export JWT_SECRET="$(openssl rand -base64 32)"1. Server: Create API Routes (Next.js App Router)
// app/api/auth/challenge/route.ts
import { createAuthHandlers } from "dero-auth/next";
const { challengeHandler } = createAuthHandlers({
domain: "myapp.com",
uri: "https://myapp.com",
jwtSecret: process.env.JWT_SECRET!,
});
export const POST = challengeHandler;// app/api/auth/verify/route.ts
import { createAuthHandlers } from "dero-auth/next";
const { verifyHandler } = createAuthHandlers({
domain: "myapp.com",
uri: "https://myapp.com",
jwtSecret: process.env.JWT_SECRET!,
});
export const POST = verifyHandler;For production deployments, use a shared nonce store (Redis/DB) via the
nonceStore option so replay protection works across multiple instances.
Production Nonce Store (Redis)
dero-auth includes a Redis-backed NonceStore adapter with atomic consume:
import { createClient } from "redis";
import { createAuthHandlers } from "dero-auth/next";
import { createRedisNonceStoreFromNodeRedis } from "dero-auth/server";
const redis = createClient({ url: process.env.REDIS_URL! });
await redis.connect();
const nonceStore = createRedisNonceStoreFromNodeRedis(redis, {
keyPrefix: "myapp:auth:nonce:",
});
const { challengeHandler, verifyHandler } = createAuthHandlers({
domain: "myapp.com",
uri: "https://myapp.com",
jwtSecret: process.env.JWT_SECRET!,
nonceStore,
});Install a Redis client of your choice in your app (redis or ioredis).
2. Client: Add the Provider and Button
// app/layout.tsx (or any parent component)
import { DeroAuthProvider } from "dero-auth/react";
export default function Layout({ children }) {
return (
<DeroAuthProvider appName="My App">
{children}
</DeroAuthProvider>
);
}// app/page.tsx (or any page)
import { SignInWithDero } from "dero-auth/react";
export default function LoginPage() {
return <SignInWithDero />;
}That's it. The button handles the full flow: wallet connection, challenge signing, and verification.
3. Custom Hook (Alternative)
If you don't want the provider pattern:
"use client";
import { useDeroAuth } from "dero-auth/react";
export default function LoginPage() {
const { signIn, signOut, isAuthenticated, address, isLoading } = useDeroAuth();
if (isAuthenticated) {
return (
<div>
<p>Signed in as {address}</p>
<button onClick={signOut}>Sign Out</button>
</div>
);
}
return (
<button onClick={signIn} disabled={isLoading}>
{isLoading ? "Connecting..." : "Sign In with DERO"}
</button>
);
}How It Works
Authentication Flow
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! | |Message Format
The message shown to the user in their wallet:
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.000ZCryptography
- Signature scheme: Schnorr signatures on BN256 (Barreto-Naehrig 254-bit curve)
- Hash function: Keccak-256, reduced modulo the curve order
- Address format: Bech32 with 33-byte compressed G1 public key
- Verification: Pure TypeScript using
@noble/curves(audited by Cure53) - No blockchain query needed: Signatures are verified mathematically, offline
Package Exports
| Import | Description |
|-----------------------|--------------------------------------|
| dero-auth | Core types and message format |
| dero-auth/crypto | Pure crypto: Schnorr verify, BN256, address parsing |
| dero-auth/server | Server SDK: challenges, verification, JWT sessions |
| dero-auth/client | Browser SDK: XSWD wallet connection, signing flow |
| dero-auth/react | React: Provider, button, hooks |
| dero-auth/next | Next.js: API handlers, auth middleware |
API Reference
Core (dero-auth)
import {
serializeMessage, // DeroAuthMessage → string
parseMessage, // string → DeroAuthMessage
validateMessage, // Check domain, nonce, expiry
generateNonce, // Crypto-random nonce string
type DeroAuthMessage,
type DeroAuthConfig,
type DeroAuthSession,
} from "dero-auth";Crypto (dero-auth/crypto)
import {
verifySignature, // Verify PEM signature → { address, message }
parsePEM, // Parse DERO PEM format
decodeAddress, // DERO address → public key
encodeAddress, // Public key → DERO address
isValidAddress, // Validate address format
reducedHash, // Keccak256 mod curve order
decompressG1, // 33 bytes → G1 point
compressG1, // G1 point → 33 bytes
} from "dero-auth/crypto";Server (dero-auth/server)
import {
createChallengeServer, // Challenge generation + nonce management
verifyAuth, // Full verification pipeline
createSessionManager, // JWT session creation/verification
} from "dero-auth/server";Client (dero-auth/client)
import {
XSWDClient, // Low-level XSWD WebSocket client
createAuthClient, // High-level auth flow client
} from "dero-auth/client";React (dero-auth/react)
import {
DeroAuthProvider, // Context provider
SignInWithDero, // Drop-in button
useDeroAuth, // Standalone hook
useDeroAuthContext, // Hook for use within provider
} from "dero-auth/react";Next.js (dero-auth/next)
import {
createAuthHandlers, // API route handlers
createDeroAuthMiddleware, // Auth middleware
getAuthAddress, // Extract address from request
} from "dero-auth/next";Protecting Routes (Next.js Middleware)
// middleware.ts
import { createDeroAuthMiddleware } from "dero-auth/next";
export const middleware = createDeroAuthMiddleware({
jwtSecret: process.env.JWT_SECRET!,
protectedPaths: ["/dashboard", "/api/protected"],
loginPath: "/login",
});
export const config = {
matcher: ["/dashboard/:path*", "/api/protected/:path*"],
};Requirements
- DERO wallet: Engram (desktop) or DERO CLI wallet with XSWD enabled
- Node.js: >= 20.19.0
- React: 18+ or 19+ (optional, for React components)
- Next.js: 14+ (optional, for Next.js helpers)
Wallet Compatibility
| Wallet | Connection | Status | |----------------|-------------|-----------| | Engram (desktop) | XSWD (ws://localhost:44326) | Supported | | DERO CLI wallet | XSWD (ws://localhost:10103) | Supported |
Why Not Just Use Ethereum Auth?
| | Ethereum (SIWE) | DERO Auth | |---|---|---| | Transaction privacy | All transactions visible on-chain | Transactions encrypted, invisible to verifier | | Wallet extension | MetaMask required | Connects to local wallet via WebSocket | | Personal data | Address links to full history | Address reveals nothing about activity | | Verification | Pure JS (ecrecover) | Pure JS (Schnorr on BN256) |
Development
# Install dependencies
npm install
# Run tests
npm test
# Type check
npx tsc --noEmit
# Build
npm run build
# Run demo app
JWT_SECRET="$(openssl rand -base64 32)" cd demo && npm install && npm run devLicense
MIT — see LICENSE
DHEBP is not affiliated with or endorsed by the DERO Project or its core developers.
