Appearance
User/Auth Module
Overview
The user module owns backend identity. Wallets are credentials; backend user_id is the product identity other modules authorize against.
Privy may create or hold a wallet for the frontend, but Privy JWTs are not Pump Party app auth. The backend accepts SIWE proof and issues Pump Party sessions.
Responsibilities
- Issue one-time SIWE challenges.
- Verify SIWE messages for EOA wallets and Porto-compatible signatures.
- Resolve verified wallets to backend users.
- Persist wallet ownership rows.
- Issue session-bound JWT access tokens.
- Issue, hash, rotate, and revoke refresh tokens.
- Support dev-only
x-user-idfallback when explicitly enabled outside production.
Boundary Rules
- The module returns authenticated user identity. Clone, economy, lifecycle, and prop ownership rules live in those modules or route adapters.
- Wallet addresses identify credentials, not clone ownership directly.
- Service-token auth is API infrastructure, not normal user auth.
- Dev fallback must not be enabled in production.
Runtime Flow
SIWE sign-in:
text
POST /auth/siwe/challenge
-> create nonce/challenge row with TTL
-> frontend signs SIWE message
-> POST /auth/siwe/verify
-> consume challenge atomically
-> verify message fields, chain, domain, nonce, signature
-> resolve or create backend user
-> upsert wallet ownership
-> issue access token and refresh tokenSession refresh:
text
POST /auth/session/refresh
-> hash presented refresh token
-> verify session family is active
-> revoke old token
-> create replacement refresh token
-> issue new access tokenRefresh-token reuse of a revoked/replaced token revokes the whole session family.
Main Code Paths
| Path | Purpose |
|---|---|
backend/src/modules/user/nonce-store.ts | Issues and consumes SIWE challenge nonces. |
backend/src/modules/user/siwe-verifier.ts | Builds/verifies SIWE messages, EOA signatures, and Porto-compatible signatures. |
backend/src/modules/user/user-resolver.ts | Resolves verified wallet identities into users and wallet rows. |
backend/src/modules/user/session-issuer.ts | Issues access/refresh tokens and rotates sessions. |
backend/src/modules/user/repositories/users.ts | User row persistence. |
backend/src/modules/user/repositories/user-wallets.ts | Wallet-to-user ownership persistence. |
backend/src/modules/user/repositories/auth-challenges.ts | Challenge persistence. |
backend/src/modules/user/repositories/sessions.ts | Session persistence and refresh-token hash storage. |
backend/src/api/auth.ts | Request authentication helpers for bearer and service-token callers. |
State And Tables
| Migration | Tables |
|---|---|
0001_initial.sql | users, user_auth_identities |
0005_user_service_auth.sql | user_wallets, auth_challenges, sessions |
| Table | Purpose |
|---|---|
users | Canonical backend user identity. |
user_wallets | Wallet address, chain, and user ownership mapping. |
auth_challenges | SIWE challenge nonce, domain, chain, address, expiry, consumed state. |
sessions | Session family, refresh-token hash, expiry, revoked/replaced state. |
Routes And Workers
| Route | Auth | Purpose |
|---|---|---|
POST /api/v1/auth/siwe/challenge | Public | Issue SIWE challenge. |
POST /api/v1/auth/siwe/verify | Public | Verify SIWE message and issue session tokens. |
POST /api/v1/auth/session/refresh | Refresh token | Rotate refresh token and issue a new access token. |
DELETE /api/v1/auth/session | Bearer/session | Revoke current session. |
GET /api/v1/me | Bearer | Return current backend user identity. |
There are no User/Auth workers.
Failure Behavior
- Challenge TTL defaults to 5 minutes.
- Access token TTL defaults to 24 hours.
- Refresh token TTL defaults to 14 days.
- SIWE verification checks exact challenge fields, allowed chain, allowed domain, nonce, and signature.
- Chain allowlist defaults to MegaETH testnet/mainnet ids configured in env.
- EOA signatures are verified with
viem. - Porto/non-EOA signatures are verified through MegaETH Porto Relay.
- Refresh-token reuse after rotation is treated as a compromise signal and revokes the session family.
- In non-production,
AUTH_DEV_FALLBACK=trueallowsx-user-id; production rejects that fallback.
Debugging Notes
- If auth fails before signature verification, inspect the stored
auth_challengesrow for nonce/domain/chain/address mismatch or expiry. - If refresh fails, inspect
sessions.revoked_at,replaced_by_session_id,family_id, and expiry. - If local API calls unexpectedly authenticate, check
AUTH_DEV_FALLBACK. - If a product route denies access after auth succeeds, debug that module's ownership rule rather than this module.
Tests
bash
cd backend
npm run typecheck
node --import tsx --test test/api-auth.test.ts test/siwe-verifier.test.ts test/sessions-repository.test.ts test/auth-challenges-repository.test.tsKnown Gaps
- Frontend still needs full cutover from legacy Privy JWT app-auth assumptions to Pump Party SIWE sessions.
- Production cookie/header conventions should be finalized with frontend integration.
- Operational alerting for unusual auth/challenge failure rates is not yet implemented.