Commit 1b1b34e
feat(auth): shared cross-node rate-limit + session store via cache service (ADR-0069 D2) (#2572)
* feat(auth): shared cross-node rate-limit + session store via cache service (ADR-0069 D2)
Multi-node deployments rate-limited per-process — better-auth's default
rateLimit store is in-memory, so each node counted independently and an
attacker could rotate nodes to bypass the limit.
- new cacheSecondaryStorage(cache): ICacheService → better-auth
SecondaryStorage (get maps undefined→null; set forwards TTL; delete).
- AuthManager: accept secondaryStorage; when present, wire it into the
betterAuth config AND flip rateLimit.storage to 'secondary-storage' so
counters go to the shared store (works with or without an explicit
rateLimit config block).
- AuthPlugin: bind the kernel `cache` service as secondaryStorage when
registered (shared across nodes iff the cache is — Redis adapter in a
cluster, memory single-node). Logs a warning when no cache service is
present so a multi-node deploy isn't silently per-process (ADR-0049
honesty).
Atomicity note (in code + changeset): ICacheService has no atomic
increment, so the get→set counter path can slightly over-count under high
concurrency — acceptable for a rate limiter and strictly better than
independent per-node counters; a future cache adapter exposing INCR can
add an increment method for exact counting.
Tests: adapter round-trip / miss→null / TTL / delete; auth-manager flips
rateLimit.storage to secondary-storage (with and without an explicit
rateLimit block). plugin-auth 6 files green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014y5kiH3aPLWtRRRGcVrXcT
* fix(auth): resolve the cache service via getServiceAsync (async-registered)
The kernel registers `cache` as an ASYNC service, so the sync
`ctx.getService('cache')` throws "Service 'cache' is async - use await"
at AuthPlugin.init — breaking bootstrap (caught by the dogfood gate,
which boots the real kernel; unit tests don't). Resolve via
`getServiceAsync` wrapped in try/catch so an absent/not-ready cache
falls to the per-process warning path instead of crashing boot.
Verified: dogfood 36 files / 181 tests green; plugin-auth units green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014y5kiH3aPLWtRRRGcVrXcT
* docs(adr-0069): mark shared multi-node rate-limit store as landed (#2572)
Reconcile the ADR-0069 implementation matrix now that the shared
secondaryStorage-backed rate-limit store has landed in this PR — moves it
from 'Remaining P2' to 'landed', leaving only per-org IP ranges (#2571)
as the remaining P2 gap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014y5kiH3aPLWtRRRGcVrXcT
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 07f055c commit 1b1b34e
7 files changed
Lines changed: 206 additions & 3 deletions
File tree
- .changeset
- docs/adr
- packages/plugins/plugin-auth/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
142 | | - | |
| 142 | + | |
143 | 143 | | |
144 | 144 | | |
145 | 145 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1806 | 1806 | | |
1807 | 1807 | | |
1808 | 1808 | | |
| 1809 | + | |
| 1810 | + | |
| 1811 | + | |
| 1812 | + | |
| 1813 | + | |
| 1814 | + | |
| 1815 | + | |
| 1816 | + | |
| 1817 | + | |
| 1818 | + | |
| 1819 | + | |
| 1820 | + | |
| 1821 | + | |
| 1822 | + | |
| 1823 | + | |
| 1824 | + | |
| 1825 | + | |
| 1826 | + | |
| 1827 | + | |
| 1828 | + | |
| 1829 | + | |
| 1830 | + | |
| 1831 | + | |
| 1832 | + | |
| 1833 | + | |
| 1834 | + | |
| 1835 | + | |
| 1836 | + | |
| 1837 | + | |
| 1838 | + | |
1809 | 1839 | | |
1810 | 1840 | | |
1811 | 1841 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
348 | 348 | | |
349 | 349 | | |
350 | 350 | | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
351 | 362 | | |
352 | 363 | | |
353 | 364 | | |
| |||
643 | 654 | | |
644 | 655 | | |
645 | 656 | | |
646 | | - | |
647 | | - | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
648 | 671 | | |
649 | 672 | | |
650 | 673 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
157 | 157 | | |
158 | 158 | | |
159 | 159 | | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
160 | 190 | | |
161 | 191 | | |
162 | 192 | | |
| |||
Lines changed: 50 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
0 commit comments