Skip to content

Pass Storefront API requests through the dev proxy as-is#7377

Open
frandiox wants to merge 2 commits intomainfrom
fd-sfapi-fix
Open

Pass Storefront API requests through the dev proxy as-is#7377
frandiox wants to merge 2 commits intomainfrom
fd-sfapi-fix

Conversation

@frandiox
Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

Requests to /api/{version|unstable}/graphql.json were returning 401 because the dev proxy injected the SFR devtools bearer via the Authorization header. The public Storefront API rejects that token — it expects X-Shopify-Storefront-Access-Token from the caller.

WHAT is this pull request doing?

Forward these requests untouched (no Authorization, Cookie, referer, or _fd/pb params) so the caller's own auth passes through. Introduces isPassthroughRequest(event) as the extension point for future pass-through rules.

How to test your changes?

Make a request to SFAPI from the Chrome dev tools. Without this PR it will return 401.

Post-release steps

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes
  • I've considered analytics changes to measure impact
  • The change is user-facing — I've identified the correct bump type (patch for bug fixes · minor for new features · major for breaking changes) and added a changeset with pnpm changeset add

frandiox and others added 2 commits April 22, 2026 18:56
Requests to /api/{version|unstable}/graphql.json were returning 401
because the dev proxy injected the SFR devtools bearer via the
Authorization header. The public Storefront API rejects that token —
it expects X-Shopify-Storefront-Access-Token from the caller.

Forward these requests untouched (no Authorization, Cookie, referer,
or _fd/pb params) so the caller's own auth passes through. Introduces
isPassthroughRequest(event) as the extension point for future
pass-through rules.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 22, 2026 17:13
@frandiox frandiox requested review from a team as code owners April 22, 2026 17:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the theme dev proxy so Storefront API GraphQL requests aren’t broken by theme-dev auth injection, preventing 401s when callers use their own Storefront API credentials.

Changes:

  • Adds a Storefront API path matcher and isPassthroughRequest(event) hook for future passthrough rules.
  • Skips adding theme auth/cookies/dev query params for /api/{version|unstable}/graphql.json requests.
  • Adds Vitest coverage for Storefront API passthrough behavior and a patch changeset.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
packages/theme/src/cli/utilities/theme-environment/proxy.ts Introduces SFAPI passthrough detection and conditionally avoids injecting theme-specific headers/query params.
packages/theme/src/cli/utilities/theme-environment/proxy.test.ts Adds tests validating the passthrough path and non-matching fallback behavior.
.changeset/itchy-jobs-report.md Patch changeset documenting the SFAPI proxy fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Cookie: buildCookies(ctx.session, {headers}),
// Only include Authorization for theme dev, not theme-extensions
...(ctx.type === 'theme' ? {Authorization: `Bearer ${ctx.session.storefrontToken}`} : {}),
})
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isPassthroughRequest skips the injection block, but the passthrough path still forwards any client-supplied cookie, authorization, and referer headers (from getProxyStorefrontHeaders(event)), and also forwards _fd/pb if they were already present in the incoming URL. This contradicts the stated intent of not sending auth/cookies/dev params to the public Storefront API, and can also leak caller Authorization tokens upstream. Consider explicitly deleting cookie/Cookie, authorization/Authorization, and referer from headers (and deleting _fd/pb from url.searchParams) when isPassthroughRequest(event) is true.

Suggested change
})
})
} else {
delete headers.cookie
delete headers.Cookie
delete headers.authorization
delete headers.Authorization
delete headers.referer
delete headers.Referer
url.searchParams.delete('_fd')
url.searchParams.delete('pb')

Copilot uses AI. Check for mistakes.
Comment on lines +430 to +451
test('forwards /api/YYYY-MM/graphql.json without injecting theme auth, cookies, referer, or dev params', async () => {
const event = createH3Event('POST', '/api/2026-01/graphql.json', {
'x-shopify-storefront-access-token': 'public-access-token',
authorization: 'Bearer client-supplied-token',
})

await proxyStorefrontRequest(event, passthroughCtx)

expect(fetchMock).toHaveBeenCalledOnce()
const [requestUrl, init] = fetchMock.mock.calls[0] as [URL, RequestInit]

expect(requestUrl.toString()).toBe('https://my-store.myshopify.com/api/2026-01/graphql.json')
expect(requestUrl.searchParams.has('_fd')).toBe(false)
expect(requestUrl.searchParams.has('pb')).toBe(false)

const headers = init.headers as Record<string, string>
expect(headers['x-shopify-storefront-access-token']).toBe('public-access-token')
expect(headers.authorization).toBe('Bearer client-supplied-token')
expect(headers.Authorization).toBeUndefined()
expect(headers.Cookie).toBeUndefined()
expect(headers.referer).toBeUndefined()
})
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The passthrough tests currently assert headers.Cookie/headers.Authorization are undefined, but getProxyStorefrontHeaders() produces lowercased keys (see existing snapshot in this file), so these assertions don’t prove that cookies/authorization aren’t being forwarded (they could still be present as headers.cookie / headers.authorization). If the goal is to ensure nothing auth/cookie-like is forwarded for SFAPI, update the test to set cookie/referer/authorization on the incoming request and assert both casings are absent (or, if forwarding caller auth is intended, clarify expectations and ensure the proxy doesn’t overwrite it).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before this gets merged let's get @EvilGenius13 to look at it who has done a bunch of header stuff recently to prevent 401 and 429s.

@frandiox frandiox requested a review from EvilGenius13 April 23, 2026 13:44
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.

4 participants