Skip to content

fix(api): support Fetch Request in getAuthProviderHeader#1750

Merged
Tobbe merged 3 commits into
cedarjs:mainfrom
bellcoTech:fix-getAuthProviderHeader-fetch-request
May 11, 2026
Merged

fix(api): support Fetch Request in getAuthProviderHeader#1750
Tobbe merged 3 commits into
cedarjs:mainfrom
bellcoTech:fix-getAuthProviderHeader-fetch-request

Conversation

@bellcoTech
Copy link
Copy Markdown
Contributor

Problem

Bearer-token auth silently fails when an @cedarjs/api handler is invoked via the Web Standard / middleware path (a Fetch Request rather than a Lambda APIGatewayProxyEvent). A request with valid auth-provider and Authorization: Bearer … headers comes back as unauthenticated, and getAuthenticationContext returns undefined — so any auth provider that uses Bearer tokens (Auth0, Supabase non-cookie, Clerk JWT, custom JWT, etc.) is broken on that path.

Root cause

getAuthProviderHeader (in packages/api/src/auth/index.ts) does:

Object.keys(event?.headers ?? {}).find(
  (key) => key.toLowerCase() === AUTH_PROVIDER_HEADER,
)

For a Lambda event, event.headers is a plain object, so Object.keys returns the header names. For a Fetch Request, event.headers is a Headers instance — Object.keys(headersInstance) returns [], the function returns undefined, and the short-circuit at the top of getAuthenticationContext decides the request is unauthenticated:

if (!typeFromHeader && !cookieHeader) {
  return undefined
}

So the Bearer-token code path is never even attempted on the middleware path.

Fix

When headers exposes a .get() method (the Headers API), look the value up directly via headers.get('auth-provider'). Fall back to the existing plain-object iteration for Lambda callers, so existing handlers behave exactly as they do today.

Surface area is intentionally tiny — one function, one file — and the Lambda path is the explicit fallback, so the change is additive rather than a behaviour swap.

Checks

Per CONTRIBUTING.md:

  • yarn check — clean (no constraint or dedupe issues)
  • yarn test in packages/api — 245 passing, including a new regression test in packages/api/src/auth/__tests__/getAuthenticationContext.test.ts that exercises Request + auth-provider header + Authorization: Bearer …
  • yarn build in packages/api — clean (ESM + CJS)
  • yarn lint — clean (via pre-commit hook)

No new dependencies.

`getAuthProviderHeader` previously called `Object.keys(event.headers)` to
locate the auth-provider header. This works for Lambda
`APIGatewayProxyEvent` (where `headers` is a plain object) but silently
returns `[]` for a Fetch `Request`, whose `headers` is a `Headers` class
instance. As a result, requests using Bearer-token auth on the new Web
Standard handler path were treated as unauthenticated even with a valid
`auth-provider` and `Authorization` header.

When `headers` exposes a `.get()` method, look the value up via the
`Headers` API directly before falling back to plain-object iteration.

Adds a regression test covering the Fetch Request + Bearer token case.
@netlify
Copy link
Copy Markdown

netlify Bot commented May 11, 2026

Deploy Preview for cedarjs canceled.

Name Link
🔨 Latest commit a0d9123
🔍 Latest deploy log https://app.netlify.com/projects/cedarjs/deploys/6a01d6ab1823790009110500

@github-actions github-actions Bot added this to the next-release-patch milestone May 11, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 11, 2026

Greptile Summary

This PR fixes a silent auth failure on the Web Standard / middleware path by correcting getAuthProviderHeader to handle a Fetch Request (whose headers is a Headers instance on which Object.keys returns []) alongside the existing Lambda plain-object path.

  • packages/api/src/auth/index.ts: Adds an early isFetchApiRequest branch that calls event.headers.get(AUTH_PROVIDER_HEADER) directly; the Lambda path is preserved as an explicit fallback, keeping the change purely additive.
  • packages/api/src/auth/__tests__/getAuthenticationContext.test.ts: Adds a new describe block that exercises the full getAuthenticationContext pipeline with a real Request object, bearer token, and an auth decoder — covering the exact regression scenario described in the PR.

Confidence Score: 5/5

Safe to merge — a narrowly scoped additive fix with a direct regression test and no changes to the Lambda path's observable behaviour.

The change is a two-branch dispatch that only adds a new code path for Fetch requests while leaving the Lambda path intact. The root cause is well understood, the fix is minimal, and the new test exercises the exact failure scenario end-to-end. No existing tests were modified, and the docs in 2026-03-26-cedarjs-project-overview.md remain accurate.

No files require special attention.

Important Files Changed

Filename Overview
packages/api/src/auth/index.ts Fixes getAuthProviderHeader to use isFetchApiRequest dispatch for Fetch Request objects; Lambda fallback is functionally correct but bypasses the existing getEventHeader helper for the return value.
packages/api/src/auth/tests/getAuthenticationContext.test.ts Adds a targeted regression test covering the Fetch Request + bearer-token path; exercises the full getAuthenticationContext pipeline and asserts all returned fields.

Reviews (3): Last reviewed commit: "minor tweaks" | Re-trigger Greptile

@Tobbe
Copy link
Copy Markdown
Member

Tobbe commented May 11, 2026

Support for webstandard fetch handlers is a work in progress. Did you see Greptile's review comment? Are they helpful?

Addresses review feedback on cedarjs#1750
flagging that the original fix duck-typed `headers.get` to detect a
Fetch `Request`, duplicating the role of the existing `isFetchApiRequest`
helper in `packages/api/src/transforms.ts`. That helper is the canonical
dispatch used elsewhere in the package (including `getEventHeader` in
`packages/api/src/event.ts`), so introducing a second detection path can
drift over time — e.g. if the ponyfill's constructor name changes or a
new Fetch-like request type appears.

Refactor `getAuthProviderHeader` to dispatch on `isFetchApiRequest`:

- Fetch `Request`: read `event.headers.get(AUTH_PROVIDER_HEADER)`
  directly. `Headers.get` is already case-insensitive, so no manual
  normalisation is needed.
- Lambda `APIGatewayProxyEvent`: keep the existing
  `Object.keys(headers).find(...)` walk. API Gateway preserves the
  client's header case in `event.headers`, so the case-insensitive
  match has to stay defensive for proper-case (`Auth-Provider`) and
  upper-case (`AUTH-PROVIDER`) clients.

Pure refactor — no behavioural change on either path. Regression test
in `getAuthenticationContext.test.ts` continues to cover the Fetch
Request + Bearer-token path.

`yarn test` in `packages/api` — 245 passing.
`yarn build` — clean (ESM + CJS).
@bellcoTech
Copy link
Copy Markdown
Contributor Author

@Tobbe Yeah, fair — greptile had a point. Refactored to dispatch on isFetchApiRequest instead, so no second detection path next to getEventHeader.
Totally get fetch handlers are still in flux — happy to park or reshape this around whatever the WIP lands on.

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented May 11, 2026

🤖 Nx Cloud AI Fix

Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci


View your CI Pipeline Execution ↗ for commit a0d9123

Command Status Duration Result
nx run-many -t build:pack --exclude create-ceda... ✅ Succeeded 5s View ↗
nx run-many -t build ✅ Succeeded 3m 58s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-11 21:44:13 UTC

@Tobbe Tobbe merged commit 085350b into cedarjs:main May 11, 2026
74 of 75 checks passed
@github-actions
Copy link
Copy Markdown

The changes in this PR are now available on npm.

Try them out by running yarn cedar upgrade -t 5.0.0-canary.2317

Or try it in a new app with yarn dlx create-cedar-app@5.0.0-canary.2317

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants