Skip to content

Commit b7a08ff

Browse files
kixelatedclaude
andauthored
relay: unified --auth-api (one call returns key + public + alias) (#1581)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e58e576 commit b7a08ff

6 files changed

Lines changed: 576 additions & 24 deletions

File tree

doc/bin/relay/auth.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,26 @@ The client's connection URL path does **not** need to match the token's `root` e
149149

150150
The connection is also rejected if the resulting permissions are empty (no publish or subscribe paths remain after scoping).
151151

152+
### Unified Auth API (`--auth-api`)
153+
154+
Instead of wiring `--auth-key-dir` (URL form) and `--auth-public-api` separately, a relay can resolve **everything it needs to authorize a connection in one call** with `--auth-api <url>` (env `MOQ_AUTH_API`, or `auth_api` under `[auth]` in TOML). It is mutually exclusive with `--auth-key`, `--auth-key-dir`, `--auth-public`, and `--auth-public-api` (configuring both is a startup error); `--auth-domain` still applies.
155+
156+
Per connection the relay issues `GET <base>?root=<path>&kid=<kid>&mtls=true` over the same cached, mTLS-gated HTTP client used by the other auth fetches. All three are query params (the base URL is used verbatim): `root` is the connection path (slashes preserved); `kid` is sent only when the connection carries a JWT (value taken from its header); `mtls=true` is sent only when the peer presented a verified client cert. The JSON response has four **optional** fields:
157+
158+
- `alias` — the canonical full root to scope this connection to: the path with its first segment (a stable id, current vanity, or recently-changed vanity) resolved to the project's canonical id, the rest of the path preserved (e.g. `demo/room/cam``x7k2qp/room/cam`). The relay uses it verbatim, so the server owns the entire mapping. Absent → the request path is used unchanged.
159+
- `public``{ "subscribe": [...], "publish": [...] }` anonymous access prefixes (relative to the root), used when there is no JWT. Absent → no public access.
160+
- `key` — the verifying JWK (a JSON object, deserialized directly) for the requested `kid`. Absent → key-not-found, and the JWT is rejected.
161+
- `internal` — the billing tier. The relay forwards `mtls=true` and lets the API decide; absent defaults to internal for mTLS peers and external for JWT/public connections. So the API can promote a first-party token to internal or demote a cert-verified connection to external.
162+
163+
This lets a project stay reachable by both its stable id and its current/old vanity path, all mapping to the same broadcast tree: with the API resolving `demo``x7k2qp`, both `cdn.moq.dev/demo/foo` and `cdn.moq.dev/x7k2qp/foo` scope to `/x7k2qp/foo`.
164+
165+
```toml
166+
[auth]
167+
auth_api = "https://api.moq.dev/cluster/auth"
168+
```
169+
170+
Unlike the standalone flags, the unified call **fails closed**: any network error, non-2xx status, or unparseable response rejects the connection. The verifying key itself comes from this call, so there is no safe fallback; the endpoint's `Cache-Control` softens transient failures. A root connection (`/`, e.g. a cluster peer) has no project segment, so mTLS peers skip the call entirely.
171+
152172
## Supported Algorithms
153173

154174
### Symmetric (HMAC)

0 commit comments

Comments
 (0)