You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(auth): IP allow-list — network gating on auth routes (ADR-0069 D5, P2)
- service-settings: new `allowed_ip_ranges` setting (Network group; CIDR/IP list).
- plugin-auth: a Hono middleware registered ahead of the better-auth handler
rejects auth requests from a client IP outside the ranges with 403
IP_NOT_ALLOWED. Client IP read trust-proxy-aware (x-forwarded-for first hop /
cf-connecting-ip / x-real-ip). /config + /bootstrap-status exempt so a blocked
client still gets a clean login + error. Fails OPEN when the IP can't be
determined (missing proxy header = no-op, not a lockout). IPv4 CIDR + exact
match (ipMatchesRange + isClientIpAllowed).
Default-off / additive; ADR-0049.
Verified live (dogfood, allowed=203.0.113.0/24): sign-in with XFF 8.8.8.8 -> 403
IP_NOT_ALLOWED; XFF 203.0.113.50 -> 200 + token; /config from a disallowed IP ->
200 (login renders); no XFF -> 200 (fail-open, admin not locked out). Unit:
plugin-auth 208 + service-settings 129 green; full build incl. strict DTS green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auth: IP allow-list — network gating on the auth routes (ADR-0069 D5, P2)
7
+
8
+
Adds an `allowed_ip_ranges` auth setting (CIDR ranges or exact IPs; empty = no restriction). A Hono middleware registered ahead of the better-auth handler in the auth-route registration rejects auth requests from a client IP outside the ranges with `403 IP_NOT_ALLOWED`, before they reach better-auth.
9
+
10
+
- Client IP is read trust-proxy-aware from `x-forwarded-for` (first hop) / `cf-connecting-ip` / `x-real-ip`.
11
+
- The public render helpers (`/config`, `/bootstrap-status`) are exempt so a blocked client still gets a clean login page + a clear error.
12
+
-**Fails OPEN** when the client IP can't be determined (no proxy header), so a misconfigured proxy is a no-op rather than a lockout — an admin enabling this must ensure forwarded headers are trusted.
Copy file name to clipboardExpand all lines: packages/services/service-settings/src/manifests/auth.manifest.ts
+15Lines changed: 15 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -266,6 +266,21 @@ const manifest = {
266
266
description: 'Cap simultaneous signed-in sessions per user; the oldest are signed out past the cap. 0 = unlimited.',
267
267
},
268
268
269
+
{
270
+
type: 'group',
271
+
id: 'network',
272
+
label: 'Network',
273
+
required: false,
274
+
description: 'Restrict where users can authenticate from.',
275
+
},
276
+
{
277
+
type: 'textarea',
278
+
key: 'allowed_ip_ranges',
279
+
label: 'Allowed IP ranges',
280
+
required: false,
281
+
description:
282
+
'CIDR ranges or exact IPs (one per line, or comma-separated), e.g. 203.0.113.0/24. When set, sign-in from outside these ranges is rejected. Empty = no restriction. Requires a trusted proxy to set X-Forwarded-For.',
0 commit comments