fix(typescript): scope passthrough fetch auth headers to base URL origin#17208
Conversation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
SDK Generation Benchmark ResultsComparing PR branch against median of 5 nightly run(s) on Full benchmark table (click to expand)
main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via |
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Description
The passthrough
client.fetch()escape hatch (makePassthroughRequest) attached the SDK's auth headers to any resolved URL, with no check that the URL targets the configured base URL. Passing an absolute cross-origin URL intoclient.fetch()therefore leaked the SDK's credentials (e.g.Authorization: Bearer <token>) to that host. This hardens the escape hatch so callers don't have to sanitize URLs themselves.Reported against a Fern-generated TS SDK (
PhenoML/phenoml-ts-sdk#209). Both affected files (makePassthroughRequest.ts,Client.ts) are Fern-generated / core-runtimeasIsfiles, so the fix belongs upstream in the generator's core-utilities where every generated TS SDK picks it up.Changes Made
Gate auth headers on same origin. In
makePassthroughRequest.ts, auth headers are attached only when the resolved request URL has the same origin as the configured base URL (or environment):Relative paths (joined onto
baseUrl) and same-origin absolute URLs are unaffected; cross-origin absolute URLs no longer receive the token. Non-auth headers (SDK defaults, init, per-request) are unchanged regardless of origin.Redact credentials in passthrough debug logs. The passthrough debug logs previously logged
url: fullUrlverbatim (unlike the mainFetcher, which usesredactUrl()). ExtractedredactUrl+SENSITIVE_QUERY_PARAMSfromFetcher.tsinto a sharedredactUrl.ts(behavior-preserving;Fetcher.tsnow imports them) and used it for both passthrough debug log lines.Changelog: added
fixentry undergenerators/typescript/sdk/changes/unreleased/.Regenerated
ts-sdkseed snapshots to reflect the template changes (env-only.fern/metadata.jsonchurn reverted).Testing
auth header origin scopingsuite inmakePassthroughRequest.test.tscovering: relative path, same-origin absolute, environment-origin match, cross-origin drop, cross-origin-by-port drop, no-baseUrl drop, and non-auth init headers preserved on cross-origin; plus a debug-log redaction test. Existing auth tests updated to set a matchingbaseUrl.--local) and ran the generated suite with vitest:makePassthroughRequest.test.ts40/40 pass;Fetcher/logging/redacting68/68 pass (confirming theredactUrlextraction is behavior-preserving). Generated SDK compiles under--isolatedDeclarations.Link to Devin session: https://app.devin.ai/sessions/994ae83694cb47a5947cbd9d0c11e68d