Skip to content

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-id fallback 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 token

Session 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 token

Refresh-token reuse of a revoked/replaced token revokes the whole session family.

Main Code Paths

PathPurpose
backend/src/modules/user/nonce-store.tsIssues and consumes SIWE challenge nonces.
backend/src/modules/user/siwe-verifier.tsBuilds/verifies SIWE messages, EOA signatures, and Porto-compatible signatures.
backend/src/modules/user/user-resolver.tsResolves verified wallet identities into users and wallet rows.
backend/src/modules/user/session-issuer.tsIssues access/refresh tokens and rotates sessions.
backend/src/modules/user/repositories/users.tsUser row persistence.
backend/src/modules/user/repositories/user-wallets.tsWallet-to-user ownership persistence.
backend/src/modules/user/repositories/auth-challenges.tsChallenge persistence.
backend/src/modules/user/repositories/sessions.tsSession persistence and refresh-token hash storage.
backend/src/api/auth.tsRequest authentication helpers for bearer and service-token callers.

State And Tables

MigrationTables
0001_initial.sqlusers, user_auth_identities
0005_user_service_auth.sqluser_wallets, auth_challenges, sessions
TablePurpose
usersCanonical backend user identity.
user_walletsWallet address, chain, and user ownership mapping.
auth_challengesSIWE challenge nonce, domain, chain, address, expiry, consumed state.
sessionsSession family, refresh-token hash, expiry, revoked/replaced state.

Routes And Workers

RouteAuthPurpose
POST /api/v1/auth/siwe/challengePublicIssue SIWE challenge.
POST /api/v1/auth/siwe/verifyPublicVerify SIWE message and issue session tokens.
POST /api/v1/auth/session/refreshRefresh tokenRotate refresh token and issue a new access token.
DELETE /api/v1/auth/sessionBearer/sessionRevoke current session.
GET /api/v1/meBearerReturn 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=true allows x-user-id; production rejects that fallback.

Debugging Notes

  • If auth fails before signature verification, inspect the stored auth_challenges row 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.ts

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