Auth Flow

The 4rho API supports two authentication paths: HMAC API keys for programmatic access and OAuth login for browser-based sessions.

HMAC API Keys (Programmatic)

API keys are the recommended authentication method for bots, market makers, and automated trading systems.

Lifecycle

  1. Issuance - An admin creates a key via the dashboard, specifying scopes, rate limit tier, and optional IP allowlist
  2. Credentials - The API key, secret, and passphrase are displayed exactly once - store them securely
  3. Usage - Every request is signed with HMAC-SHA256 (see Authentication)
  4. Rotation - Keys can be rotated without downtime; the old key is revoked and new credentials are issued
  5. Revocation - Keys can be revoked immediately by an admin

Key Properties

PropertyDescription
API KeyPublic identifier, prefixed with 4rho_sk_
SecretUsed to derive the HMAC signing key
PassphraseSent as a header on every request
ScopesGranular permissions (e.g., trade:orders)
Rate Limit Tierstandard (10/s), market_maker (100/s), premium (50/s)
IP AllowlistOptional - restricts usage to specific IPs
ExpirationOptional - keys can have an expiry date

OAuth Login (Browser)

For browser-based applications, existing 4rho accounts can sign in through Google or GitHub OAuth. Brand-new accounts must use the DOB-gated Create account / Privy flow; an unknown OAuth subject is rejected before user or session creation.

Flow

  1. Generate a 32-byte random, lowercase-hex CSRF state and retain it for the callback
  2. GET /v1/auth/oauth/:provider?state=... - Stores that exact state once and redirects to the provider's consent page
  3. Provider redirects back with an authorization code and the same state
  4. Compare the returned state locally, then POST /v1/auth/callback to exchange the code for a 4rho browser session
  5. The access and refresh credentials are set only as Secure, HTTP-only cookies

The 4rho web app performs both calls through the same-origin /api/v1/auth/oauth/:provider and /api/v1/auth/callback BFF routes. OAuth state is provider-bound and single-use on the backend; callbacks initiated before an explicit browser logout are rejected by the web app's durable logout epoch before any code exchange is dispatched.

Token Lifecycle

EndpointDescription
POST /v1/auth/refreshExchange a valid refresh token for new tokens
POST /v1/auth/revokeRevoke a specific refresh token
POST /v1/auth/revoke-allRevoke all sessions for the current user
POST /v1/auth/logoutClear session cookies and revoke tokens

Token Details

  • Access token - Short-lived JWT (~15 minutes), carried only by the HTTP-only access cookie; raw Bearer JWT authentication is rejected
  • Refresh token - Longer-lived (~7 days), carried only by the HTTP-only refresh cookie and used to rotate the session
  • CSRF token - Double-submit token required for browser mutations, obtained via GET /v1/user/csrf-token

Wallet Linking

Authenticated users can link additional wallets via the wallet management endpoints:

  1. GET /v1/wallets/link/nonce - Get a nonce for the wallet to link (requires manage:account)
  2. POST /v1/wallets/link - Submit the signed message to link the wallet (requires manage:account)
  3. GET /v1/wallets - List all linked wallets (requires read:account)
  4. DELETE /v1/wallets/:id - Unlink a wallet (requires manage:account)
  5. PUT /v1/wallets/:id/primary - Set a wallet as primary (requires manage:account)

MFA (Multi-Factor Authentication)

Users with manage:account scope can manage MFA:

EndpointScopeDescription
GET /v1/auth/mfa/statusread:accountCheck MFA enrollment status
POST /v1/auth/mfa/setupmanage:accountBegin TOTP enrollment
POST /v1/auth/mfa/verify-setupmanage:accountConfirm TOTP code and enable
POST /v1/auth/mfa/verifymanage:accountVerify a TOTP code
POST /v1/auth/mfa/disablemanage:accountDisable MFA
POST /v1/auth/mfa/recoverymanage:accountUse a recovery code

Admin routes can require MFA by setting ADMIN_MFA_REQUIRED=true. When enabled, admin endpoints return 403 unless the user has verified MFA in the current session.

Admin Check

GET /v1/auth/is-admin

Scope: read:account

Check whether the authenticated user has admin privileges.

Response

{
  "isAdmin": true,
  "role": "super_admin",
  "permissions": ["view_users", "manage_users", "view_aml", "manage_aml"],
  "mfa": {
    "enabled": true,
    "verified": true
  }
}
FieldTypeDescription
isAdminboolTrue when the user is an admin (any role).
rolestringOne of support, ops, risk, finance, super_admin.
permissionsstring[]RBAC permissions granted to the user's role.
mfa.enabledboolWhether MFA is configured on the account.
mfa.verifiedboolWhether the current session has cleared MFA.