Skip to content

Commit c42164f

Browse files
committed
chore(changeset): the auth IP allow-list judges the established client address
Also keeps the package root's export surface unchanged: the rule is reached only through the ./client-address entry. Claude-Session: https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4ebc356 commit c42164f

2 files changed

Lines changed: 29 additions & 3 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
'@objectstack/plugin-auth': patch
3+
'@objectstack/runtime': patch
4+
'@objectstack/cli': patch
5+
'@objectstack/service-settings': patch
6+
---
7+
8+
fix(plugin-auth): the auth IP allow-list judges the client address the server established (#24739)
9+
10+
Clause-②: no
11+
12+
The `allowed_ip_ranges` auth setting (ADR-0069 D5) and the `last_login_ip` login audit (D7) now establish a request's client address by the same rule as the inbound rate limiter: `X-Forwarded-For` (its first entry), then `X-Real-IP`, count only when the stack declares `server.trustProxy`. Otherwise the address is the connection's peer address.
13+
14+
**For operators who set `allowed_ip_ranges`:**
15+
16+
- Behind a reverse proxy or load balancer, declare `server: { trustProxy: true }` in the stack before you upgrade. Without it, the allow-list judges the proxy's own address for every request.
17+
- A request whose client address cannot be established (the transport reports no peer address, and no forwarded header is trusted) is now refused with `403 IP_NOT_ALLOWED`. Before, it was admitted. The first such refusal logs a warning that names `allowed_ip_ranges` and `server.trustProxy`.
18+
- `CF-Connecting-IP` is no longer read. Behind Cloudflare, declare `server.trustProxy`, and the `X-Forwarded-For` it sets is used.
19+
- A dual-stack listener reports an IPv4 client in IPv4-mapped form (`::ffff:203.0.113.7`). That address is now matched as the IPv4 address it denotes.
20+
- With `allowed_ip_ranges` unset or empty, nothing changes.
21+
22+
**`last_login_ip`** records the address the allow-list judged, or no address when none could be established. It is no longer read from a forwarded header the deployment does not trust.
23+
24+
**By package:**
25+
26+
- `@objectstack/plugin-auth`: the rule is published as the dependency-free `@objectstack/plugin-auth/client-address` entry (`resolveClientAddress`). `AuthPlugin` and `AuthManager` take a `trustProxy` option. `AuthManager.handleRequest` takes an optional second argument that carries the transport's `remoteAddress`.
27+
- `@objectstack/runtime`: the inbound rate limiter imports the rule from that entry instead of keeping its own copy. Its keys are unchanged.
28+
- `@objectstack/cli`: `objectstack serve` passes the stack's `server.trustProxy` to `AuthPlugin` as well as to the dispatcher. A host that composes `AuthPlugin` itself passes `trustProxy` the same way.
29+
- `@objectstack/service-settings`: the `allowed_ip_ranges` help text says which address is judged.

‎packages/plugins/plugin-auth/src/index.ts‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,6 @@ export * from './otp-send-guard.js';
6161
// of record out of `sys_session`, which disables the ADR-0069 D4 session
6262
// controls, so a host opts into that trade explicitly or not at all.
6363
export * from './rate-limit-storage.js';
64-
// The client-address trust rule shared with the runtime's inbound rate limiter
65-
// (also published as the dependency-free `./client-address` subpath).
66-
export * from './client-address.js';
6764
export * from './secondary-storage.js';
6865
export * from './register-sso-provider.js';
6966
export * from './send-verification-email.js';

0 commit comments

Comments
 (0)