Skip to content

Rate Limits

middleware/rate_limit.go wires Fiber limiters backed by Redis. Each limiter uses utils.ClientIP(c) as the key so IPv4 and IPv6 clients share the same budgeting behaviour.

Tier 1 – Critical Auth

AuthLimiter, RegisterLimiter, MFAVerifyLimiter, AdminRecoveryLimiter — protects login and MFA endpoints from brute force.

Tier 2 – Share Links

ShareLinkPublicLimiter, ShareLinkCreateLimiter — guards anonymous share-link traffic and token creation.

Tier 3 – Heavy Ops

SearchLimiter, ImportExportLimiter, BulkImportLimiter, AttachmentUploadLimiter — expensive operations touching PostgreSQL or large payloads.

Tier 4 – CRUD & Collaboration

StandardCRUDLimiter, CollaborationLimiter — day-to-day note operations and collaborator management.

Tier 5 – Lightweight

LightweightLimiter — status checks such as GET /auth/mfa/status or user settings fetches.

Tier 1: 10 requests / 5 minutes (registration 5 / 15 min, admin recovery 3 / 15 min)
Tier 2: 20 requests / 5 minutes (public share) and 10 / 15 minutes (create)
Tier 3: 30 requests / minute (search), 10 / 5 minutes (import/export), 5 / 15 minutes (bulk import)
Tier 4: 100 requests / minute (CRUD), 50 / minute (collaboration)
Tier 5: 300 requests / minute (status/endpoints)

Adjust numbers in middleware/rate_limit.go if your deployment demands different ceilings. All limiters share the same Redis connection used for sessions.

POST /auth/login, POST /auth/password/reset-*, and POST /auth/mfa/* all use Tier 1 limiters.

Limiters reuse the app Redis client. When Redis is unavailable every limiter returns HTTP 429 with "error": "Too many requests..." until the connection stabilizes.

storage := redisstorage.NewFromConnection(rdb)
limiter.New(limiter.Config{
Max: 10,
Expiration: 5 * time.Minute,
Storage: storage,
})

Deployments with sharded Redis should point REDIS_URL at a single node or use a proxy that supports INCR across the cluster; the limiter storage expects atomic increments.

  • Increase budgets via environment toggles? Expose new values through config and match them in the limiter constructors.
  • Want adaptive limits per plan? Extend middleware/rate_limit.go to consider user_id and attach multiple keys (e.g., ip:user).
  • For debugging, disable limiters in development by wrapping them in if config.Environment == "development".
if cfg.Environment == "development" {
return func(c *fiber.Ctx) error { return c.Next() }
}