Skip to main content

Security Model

Zero-Dependency Security

Kyqu implements all security primitives using Node.js built-in modules — no external security libraries.

FeatureImplementationModule
Password hashingscrypt with 16-byte salt, 64-byte keynode:crypto
Token hashingSHA-256node:crypto
TOTP 2FAHMAC-SHA1, 30-second window, RFC 6238node:crypto
CSRF protectionDouble-submit cookie patternnode:crypto timingSafeEqual
Session tokens32-byte random, URL-safe base64node:crypto randomBytes
SMTP emailRaw TCP/TLS sockets, EHLO/STARTTLS/AUTH LOGINnode:net node:tls

Password Storage

Format: scrypt:<base64url-salt>:<base64url-derived-key>
Example: scrypt:abc123...:def456...
  • Salt: 16 random bytes per password
  • Key: 64 bytes scrypt output
  • Comparison: timingSafeEqual (constant-time)

Session Security

Admin Sessions

  • Stored as HttpOnly cookies with SameSite=Strict
  • Token is 32 bytes of randomness (256 bits entropy)
  • Only SHA-256 hash stored in database
  • Raw token never logged or stored

Project User Sessions

  • Returned as bearer tokens to the integrating application
  • Same 256-bit entropy token
  • Only SHA-256 hash stored in database

CSRF Protection

Uses the double-submit cookie pattern:

  1. Server sets a non-HttpOnly kyqu_csrf cookie
  2. Client reads the cookie and includes it as x-kyqu-csrf-token header
  3. Server compares cookie vs header using timingSafeEqual
  4. Applies to all POST/PATCH/PUT/DELETE requests to admin routes
  5. Cookie rotates on each login/signup

Rate Limiting

Route families are rate-limited independently:

Route FamilyExamples
admin-login/api/admin/login
admin-signup/api/admin/signup
project-login/api/projects/*/auth/login
project-signup/api/projects/*/auth/signup
password-reset/api/projects/*/auth/password-reset/*
magic-link/api/projects/*/auth/magic-link/*
apiEverything else

Storage Backends

  • Memory (Map): Single-process development
  • PostgreSQL (api_rate_limits table): Multi-process production

Account Lockout

Per-project configurable lockout policy:

  • Tracks consecutive failed login attempts (password and failed TOTP/backup-code after correct password)
  • Locks account after lockout_max_attempts (default: 5)
  • Lockout window: lockout_window_minutes (default: 15)
  • Emits user.login_failed and user.locked webhooks
  • Admin can unlock individual user accounts
  • Superadmin can suspend entire projects — suspended projects reject all auth routes

CORS

  • Admin routes: CORS restricted to APP_ORIGIN value(s)
  • Project routes: CORS resolved per-project from allowed_origins setting
  • Empty allowed_origins = unrestricted — echoes request Origin only (never * with credentials)
  • Restricted list: only matching origins are echoed back

API Key Authentication

Projects authenticate API calls using:

  • x-kyqu-public-key header — identifies the project (public key)
  • publicKey field in request body — alternative for non-browser clients

The public key is stored in plaintext; the paired secret key is stored only as a hash.

Monitoring & Logging

  • Structured JSON logs to stdout/stderr
  • Sensitive fields (password, token, secret, key, session) automatically redacted as [redacted]
  • Optional external monitoring webhook for critical events
  • Rate limit exceeded events trigger monitoring alerts

Webhook URL Policy

Outbound webhook URLs are validated on create/update. Targets on localhost, .local hostnames, and private/link-local IP literals are rejected to reduce SSRF risk.

Email verification, password reset, and magic-link messages embed URLs pointing to the Kyqu API. The base URL is determined by your Kyqu instance configuration.

Integration Security Checklist

  • HTTPS for all API communication
  • Session tokens stored securely (keychain, HttpOnly cookies, or env vars)
  • Webhook signatures verified on your endpoints
  • CORS origins restricted in project settings
  • 401 responses handled with proper redirects
  • withAutoRefresh used for long-lived sessions