Auth Server
Dedicated authentication server — routes, security model, and setup
Overview
StarkFi includes a dedicated authentication server (server/) that bridges Privy authentication to app-managed Starknet wallets. It ensures the CLI client never directly processes or stores sensitive Privy API keys.
The server is built with Hono and handles four critical functions:
- Email OTP — Sends and verifies one-time passwords via Privy
- Wallet Management — Creates and retrieves app-managed Starknet wallets
- Transaction Signing — Proxies signing requests to Privy's Trusted Execution Environment (TEE)
- Paymaster Proxy — Forwards gas abstraction requests to the AVNU Paymaster
Important: The auth server must be running before using any StarkFi CLI or MCP commands.
Security Model
The server employs a strict security architecture designed around access minimization and key isolation:
| Security Layer | How It Works |
|---|---|
| TEE Isolation | Private keys generated by Privy never leave the Trusted Execution Environment. Neither the server nor the CLI can access raw key material. |
| JWT Authorization | All signing and paymaster endpoints require a valid JWT. Tokens are issued on successful OTP verification with a 7-day expiration. |
| Rate Limiting | Auth endpoints: 5 req/min per IP. Signing endpoints: 30 req/min per IP. |
| CORS | Configurable allowlist via ALLOWED_ORIGINS environment variable. |
| Secure Headers | X-Content-Type-Options, X-Frame-Options, and other security headers applied globally. |
| Body Limit | Maximum 1 MB request body size to prevent abuse. |
| Graceful Shutdown | Handles SIGTERM/SIGINT with a 5-second force-kill timeout. |
API Endpoints
Authentication
| Endpoint | Auth | Rate Limit | Description |
|---|---|---|---|
POST /auth/login | None | 5 req/min | Sends an email OTP to the provided address. |
POST /auth/verify | None | 5 req/min | Validates the OTP, provisions a wallet, and returns a JWT. |
Wallet
| Endpoint | Auth | Rate Limit | Description |
|---|---|---|---|
POST /wallet/find | JWT | — | Retrieves the Starknet wallet address for the authenticated user. |
POST /wallet/create | JWT | — | Creates a new app-managed Starknet wallet. |
Transaction Signing
| Endpoint | Auth | Rate Limit | Description |
|---|---|---|---|
POST /sign/hash | JWT | 30 req/min | Signs a raw Starknet payload hash via Privy TEE. |
POST /sign/message | JWT | 30 req/min | Signs a standard message via Privy TEE. |
Paymaster
| Endpoint | Auth | Rate Limit | Description |
|---|---|---|---|
POST /paymaster | JWT | — | Proxies gas abstraction requests to the AVNU Paymaster. |
Health
| Endpoint | Auth | Description |
|---|---|---|
GET / | None | Returns server name, version, and status. |
GET /health | None | Basic uptime probe for monitoring. |
Environment Variables
| Variable | Required | Description |
|---|---|---|
PRIVY_APP_ID | Yes | Application ID from the Privy Dashboard. |
PRIVY_APP_SECRET | Yes | Secret key for app-managed wallet access. Keep this secure. |
JWT_SECRET | Yes | High-entropy string (32+ characters) for JWT signing. |
PORT | No | Server port. Defaults to 3001. |
ALLOWED_ORIGINS | No | Comma-separated domains for CORS (e.g., https://starkfi.app). |
AVNU_API_KEY | No | AVNU Paymaster API key. Required for developer-sponsored (gasfree) transactions. |
Local Setup
cd server
pnpm install
cp .env.example .env # Configure your environment variables
pnpm devThe server starts at http://localhost:3001 by default.
Verify It's Running
curl http://localhost:3001/health
# → {"status":"ok"}Middleware Stack
All requests pass through the following middleware in order:
| Middleware | Purpose |
|---|---|
requestId() | Assigns a unique ID for request tracing |
logger() | Logs incoming requests to stdout |
secureHeaders() | Applies security headers |
bodyLimit() | Enforces 1 MB max body size |
cors() | CORS with configurable origin allowlist |
Authentication Flow
CLI Auth Server Privy
│ │ │
├─ POST /auth/login ─────▶│── sendOTP() ──────────▶│
│ │ │
│ (user checks email) │ │
│ │ │
├─ POST /auth/verify ────▶│── verifyOTP() ────────▶│
│ │◀─ walletId + pubKey ───│
│◀─ JWT + session ────────│ │
│ │ │
├─ POST /sign/hash ──────▶│── sign(hash) ─────────▶│ (TEE)
│◀─ signature ────────────│◀─ signature ──────────│The CLI stores the JWT locally and attaches it to all subsequent requests. Private keys never leave Privy's TEE — the server only proxies signing requests.
Last updated on