StarkFiStarkFi

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:

  1. Email OTP — Sends and verifies one-time passwords via Privy
  2. Wallet Management — Creates and retrieves app-managed Starknet wallets
  3. Transaction Signing — Proxies signing requests to Privy's Trusted Execution Environment (TEE)
  4. 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 LayerHow It Works
TEE IsolationPrivate keys generated by Privy never leave the Trusted Execution Environment. Neither the server nor the CLI can access raw key material.
JWT AuthorizationAll signing and paymaster endpoints require a valid JWT. Tokens are issued on successful OTP verification with a 7-day expiration.
Rate LimitingAuth endpoints: 5 req/min per IP. Signing endpoints: 30 req/min per IP.
CORSConfigurable allowlist via ALLOWED_ORIGINS environment variable.
Secure HeadersX-Content-Type-Options, X-Frame-Options, and other security headers applied globally.
Body LimitMaximum 1 MB request body size to prevent abuse.
Graceful ShutdownHandles SIGTERM/SIGINT with a 5-second force-kill timeout.

API Endpoints

Authentication

EndpointAuthRate LimitDescription
POST /auth/loginNone5 req/minSends an email OTP to the provided address.
POST /auth/verifyNone5 req/minValidates the OTP, provisions a wallet, and returns a JWT.

Wallet

EndpointAuthRate LimitDescription
POST /wallet/findJWTRetrieves the Starknet wallet address for the authenticated user.
POST /wallet/createJWTCreates a new app-managed Starknet wallet.

Transaction Signing

EndpointAuthRate LimitDescription
POST /sign/hashJWT30 req/minSigns a raw Starknet payload hash via Privy TEE.
POST /sign/messageJWT30 req/minSigns a standard message via Privy TEE.

Paymaster

EndpointAuthRate LimitDescription
POST /paymasterJWTProxies gas abstraction requests to the AVNU Paymaster.

Health

EndpointAuthDescription
GET /NoneReturns server name, version, and status.
GET /healthNoneBasic uptime probe for monitoring.

Environment Variables

VariableRequiredDescription
PRIVY_APP_IDYesApplication ID from the Privy Dashboard.
PRIVY_APP_SECRETYesSecret key for app-managed wallet access. Keep this secure.
JWT_SECRETYesHigh-entropy string (32+ characters) for JWT signing.
PORTNoServer port. Defaults to 3001.
ALLOWED_ORIGINSNoComma-separated domains for CORS (e.g., https://starkfi.app).
AVNU_API_KEYNoAVNU Paymaster API key. Required for developer-sponsored (gasfree) transactions.

Local Setup

cd server
pnpm install
cp .env.example .env   # Configure your environment variables
pnpm dev

The 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:

MiddlewarePurpose
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.

Edit on GitHub

Last updated on

On this page