Skip to content

feat(rate-limit): read the per-flow limits from system config - #310

Merged
Bccorb merged 2 commits into
mainfrom
feat/flow-rate-limits
Sep 13, 2026
Merged

Bccorb merged 2 commits into
mainfrom
feat/flow-rate-limits

Conversation

@Bccorb

@Bccorb Bccorb commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Part of the mobile track (fells-code/seamless-templates#40). On the published @seamless-auth/types 0.22.0; the lockfile carries it as of the last commit.

What changes

  • src/middleware/rateLimit.ts: the six flow limiters (otpIpLimiter, otpIdentityLimiter, magicLinkIpLimiter, magicLinkEmailLimiter, oauthIpLimiter, oauthProviderLimiter) read flow_rate_limits from system config instead of carrying constants. express-rate-limit takes the limit as a function but the window only as a number, so createFlowLimiter builds one limiter per configured windowSeconds on first use and keeps it; a changed limit takes effect on the next request, a changed window starts fresh counters. Key generators and the JSON 429 body are unchanged.
  • Config plumbing: SYSTEM_CONFIG_DEFAULTS.flow_rate_limits = DefaultFlowRateLimits, SYSTEM_CONFIG_ENV_MAP.flow_rate_limits = 'FLOW_RATE_LIMITS', JSON parse case, .env.example entry. bootstrapSystemConfig seeds the row on next boot for an existing instance, so no migration.
  • openapi.json / src/generated/api.ts regenerated: the system config routes gain the key.
  • Why: per-IP limits are what a mobile audience trips first. Carriers put thousands of subscribers behind one IPv4 address, so otp.perIp: 10 refuses a phone audience at modest scale while never troubling a web one. Operators raise perIp and leave perIdentity alone. Defaults are exactly the previous constants, so nothing changes for a deployment that sets nothing.

Docs

  • docs/api-contract.md: new Native and mobile clients section: RP ID and origins for iOS (https://<rpid>) and Android (android:apk-key-hash:<base64url>), keep the web origin first, magic link and OAuth destinations for apps, the tenant-wide session lifetime caveat, refresh reuse detection, authenticator policy defaults.
  • docs/configuration.md: table row plus a Flow rate limits section.
  • docs/ecosystem.md: @seamless-auth/client and @seamless-auth/react-native join @seamless-auth/react as Tier 1 dependents (one repo, three packages).

Contract-affecting per CLAUDE.md: a new system config key. Dependents: @seamless-auth/types (done in #68), admin dashboard (renders system config; unknown keys are additive), server adapter passes the system config PATCH through untouched.

Test plan

  • npm run typecheck, npm run lint, npm run check:changeset-bump
  • npm run test:run: 1472 passing (rate limiter suite rewritten for lazy, config-driven limiters: historical defaults per limiter, per-flow override, live limit change without rebuild, one limiter per window, key generators, JSON refusal body across all eight limiters)
  • npm run generate:api committed
  • npm install after the types release to update the lockfile, then ready for review

The OTP, magic link and OAuth limiters carried their values as constants:
10 OTP sends and 20 magic links per IP per 15 minutes, 5 per address, 30
OAuth starts per IP and 10 per provider. Those suit a web audience and refuse
a mobile one, because carriers put thousands of subscribers behind one IPv4
address.

The six limiters read flow_rate_limits from system config, an object whose
defaults are exactly those constants, so an instance that sets nothing behaves
as it did. express-rate-limit takes the limit as a function but the window
only as a number, so one limiter is built per configured window on first use;
a changed limit applies on the next request.

@seamless-auth/types moves to 0.22.0 for the key. Docs gain a native and
mobile clients section in api-contract.md, a flow rate limits section in
configuration.md, and the client SDK packages in ecosystem.md.
@Bccorb
Bccorb force-pushed the feat/flow-rate-limits branch from 84be3dc to bf85910 Compare September 13, 2026 16:22
@Bccorb
Bccorb marked this pull request as ready for review September 13, 2026 16:46
@Bccorb
Bccorb merged commit 5bf51ca into main Sep 13, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant