feat(agent-bff): request-edge wiring (timezone + CORS + auth-mode precedence)#1731
Merged
nbouliol merged 6 commits intoJul 2, 2026
Conversation
…cedence)
Add a hardened /agent/* request edge with a structured
{ error: { type, status, message, details? } } contract:
- Auth-mode precedence: oauth (Bearer) vs api-key (X-Forest-Bff-Key);
both -> ambiguous_credentials, neither -> unauthorized. bff_access
validated at the edge (expired -> session_expired, bad -> unauthorized).
- CORS: hand-rolled exact-origin allow-list (no wildcard) driven by
BFF_ALLOWED_ORIGINS, applied globally incl. POST /oauth/token; per-key
layer-2 intersection (api-key) -> origin_not_allowed.
- Timezone: header -> body -> BFF_DEFAULT_TIMEZONE, IANA-validated and
injected into the (stubbed) agent query; missing/invalid -> 400.
- Single shared error middleware; api-key-middleware now throws.
Fixes PRD-666
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- extractBearerToken: case-insensitive Bearer scheme (RFC 7235) - originAllowed: normalize per-key allowedOrigins from SaaS before compare - /agent chain: fail closed (401) for api-key mode when resolver unconfigured - error middleware precedes bodyParser and serializes malformed-body 4xx into the structured error contract - README/.env.example: document BFF_TOKEN_ENCRYPTION_KEY (gates OAuth) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4 new issues
|
|
Coverage Impact ⬆️ Merging this pull request will increase total coverage on Modified Files with Diff Coverage (14) 🛟 Help
|
… contract - README: without BFF_TOKEN_ENCRYPTION_KEY only /oauth/* issuance is disabled; already-issued bff_access tokens still authenticate on /agent/* - api-key-middleware: document that it rethrows ApiKeyError and must sit behind an error middleware Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- cli-core: agent edge disabled without FOREST_AUTH_SECRET, malformed BFF_ALLOWED_ORIGINS warning, api-key guard pass-through for oauth mode, non-agent path skipping the agent chain - timezone-middleware: body-field resolution incl. non-string fallback Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tonours
reviewed
Jul 2, 2026
…apping - timezone: cache canonical IANA form (resolvedOptions().timeZone) not the raw value, so case variants can't grow the validation Set without bound - auth-mode: verify with ignoreExpiration then check type before expiry, so a wrong-typed token is unauthorized (not session_expired) - error middleware: map known client statuses (413, 415) to their own type instead of a blanket invalid_request - bff-http-error: drop dead retryAfter field and unused BffErrorType union Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
With ignoreExpiration enabled, a token missing exp would be accepted indefinitely; treat a missing/non-numeric exp as unauthorized. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tonours
approved these changes
Jul 2, 2026
forest-bot
added a commit
that referenced
this pull request
Jul 2, 2026
# @forestadmin/agent-bff [1.4.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent-bff@1.3.0...@forestadmin/agent-bff@1.4.0) (2026-07-02) ### Features * **agent-bff:** request-edge wiring (timezone + CORS + auth-mode precedence) ([#1731](#1731)) ([4ba9402](4ba9402))
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Adds a hardened
/agent/*request edge toagent-bffwith a structured, type-first error contract ({ error: { type, status, message, details? } }) so consumers branch onerror.typeinstead of message text.Scope
oauth(Bearer) vsapi-key(X-Forest-Bff-Key), mutually exclusive per request: both →400 ambiguous_credentials, neither →401 unauthorized.bff_accessvalidated at the edge (expired →session_expired, bad →unauthorized). Fails closed (401) for api-key mode when the resolver is unconfigured.BFF_ALLOWED_ORIGINS, applied globally incl.POST /oauth/token; preflight short-circuits before auth. Per-key layer-2 intersection (api-key) →403 origin_not_allowed.BFF_DEFAULT_TIMEZONE, IANA-validated (mirrors the agent), injected into the (stubbed) agent query; missing →400 missing_timezone, invalid →400 invalid_timezone.api-key-middlewarenow throws; malformed/agentbodies serialized into the structured shape.The real agent proxy is Slice 3; the edge terminates in a
501stub that exposes the built query for tests.Notes / decisions
/oauth/*keep RFC-6749 error shape;session_invalidatedstays a/oauth/tokenrefresh-reuse error.bff_access(≤15 min) remains usable at the edge after reuse-invalidation (standard short-lived-token trade-off) — documented in the README.Test plan
yarn workspace @forestadmin/agent-bff test— 353 passing (auth precedence, CORS layers + preflight, timezone resolution + injection, full error-contract suite, config parsing).yarn workspace @forestadmin/agent-bff lint/build— clean.Fixes PRD-666
🤖 Generated with Claude Code
Note
Wire request edge for /agent/* with timezone, CORS, and auth-mode precedence in agent-bff
/agent/*routes in cli-core.ts: CORS, structured error handling, auth-mode resolution, per-key origin enforcement, and timezone resolution are applied in order before reaching the agent stub.createAuthModeMiddleware) resolves OAuth vs API-key from request headers, validates HS256-signedbff_accesstokens, and throws structured errors (400 ambiguous_credentials,401 unauthorized,401 session_expired) on failure.BFF_ALLOWED_ORIGINS; per-key origin restrictions add a second layer for API-key authenticated requests.X-Forest-Timezoneheader, request body, orBFF_DEFAULT_TIMEZONEfallback; invalid or missing values return structured 4xx errors.BffHttpErrorinstances to a consistent structured body; unknown errors map to500 internal_error.FOREST_AUTH_SECRETis absent, and API-key requests fail closed with401if no resolver is configured.Changes since #1731 opened
verifyBffAccessutility to separate signature verification from expiration checking, validating token type ('bff_access') before manually inspecting theexpclaim [75b8fb1]createErrorMiddlewarefactory [75b8fb1]isValidTimezoneutility to cache canonical timezone names instead of raw input values [75b8fb1]auth-mode-middleware.verifyBffAccessto verify theexpclaim is a number before checking token expiry, rejecting tokens with non-numeric or missingexpclaims with unauthorized status [55db5ef]Macroscope summarized 34c3be4.