From 2e95d91093136eb7184a089c2916062c80e1bc02 Mon Sep 17 00:00:00 2001 From: GyeongSu Han Date: Sun, 1 Mar 2026 23:32:28 +0900 Subject: [PATCH] fix: restore Accept header and prevent encoded response in GitHub OAuth token request (regression from #14061) (#14538) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## πŸ“ Summary This PR fixes a regression that caused the following error during GitHub OAuth login: > Unable to parse JSON response from [https://github.com/login/oauth/access_token](https://github.com/login/oauth/access_token) Related issue: [https://github.com/toeverything/AFFiNE/issues/14334](https://github.com/toeverything/AFFiNE/issues/14334) Regression introduced in: [https://github.com/toeverything/AFFiNE/pull/14061](https://github.com/toeverything/AFFiNE/pull/14061) --- ## 🎯 Background GitHub’s OAuth access token endpoint returns different response formats depending on the request headers. To receive a JSON response, the request must include: ``` Accept: application/json ``` If the `Accept` header is missing, GitHub responds with: ``` application/x-www-form-urlencoded ``` The current implementation assumes a JSON response and parses it directly. When a non-JSON response is returned, JSON parsing fails, breaking the OAuth login flow. --- ## πŸ” Traffic Analysis (tcpdump) Network path: affine-graphql β†’ (HTTPS) β†’ envoy β†’ (HTTP, tcpdump) β†’ envoy β†’ GitHub ### Observed Request ``` POST /login/oauth/access_token HTTP/1.1 host: github-proxy.com content-type: application/x-www-form-urlencoded accept: */* ... ``` ### Observed Response ``` HTTP/1.1 200 OK date: Sat, 28 Feb 2026 14:47:43 GMT content-type: application/x-www-form-urlencoded; charset=utf-8 ... ``` The `Accept` header was `*/*` instead of `application/json`, causing GitHub to return a form-urlencoded response. --- ## πŸ› Root Cause PR #14061 introduced a side effect in the request configuration. Although the `Accept` header was initially defined, the request options were later overwritten by the `init` parameter. Because `init.headers` replaced the previously defined headers object, the required header was lost. Resulting in: * Missing `Accept: application/json` * GitHub returning `application/x-www-form-urlencoded` * JSON parsing failure * OAuth login failure --- ## πŸ”§ Changes ### 1️⃣ Fix header overwrite order * Process the incoming `init` parameter first * Explicitly overwrite required headers afterward * Ensure `Accept: application/json` is always enforced --- ## πŸ’₯ Breaking Changes None. --- ## πŸ§ͺ How to Test 1. Configure GitHub OAuth. 2. Attempt login via GitHub. 3. Verify that: * The request contains `Accept: application/json` * The response content-type is `application/json` * No JSON parsing error occurs * OAuth login completes successfully --- ## πŸ“Œ Notes This change restores correct OAuth behavior and prevents regression caused by header overwriting introduced in #14061. The same header overwrite pattern identified in this issue was also found in the calendar module and has been corrected there as well. ## Summary by CodeRabbit * **Refactor** * Improved backend HTTP header handling for external integrations to avoid unintended header overrides, ensuring content-type and encoding hints are applied consistently and improving reliability of service requests. --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- packages/backend/server/src/plugins/calendar/providers/def.ts | 2 +- packages/backend/server/src/plugins/oauth/providers/def.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/server/src/plugins/calendar/providers/def.ts b/packages/backend/server/src/plugins/calendar/providers/def.ts index a9089d2ab6..02ad30482a 100644 --- a/packages/backend/server/src/plugins/calendar/providers/def.ts +++ b/packages/backend/server/src/plugins/calendar/providers/def.ts @@ -154,8 +154,8 @@ export abstract class CalendarProvider { protected async fetchJson(url: string, init?: RequestInit) { const response = await fetch(url, { - headers: { Accept: 'application/json', ...init?.headers }, ...init, + headers: { ...init?.headers, Accept: 'application/json' }, }); const body = await response.text(); if (!response.ok) { diff --git a/packages/backend/server/src/plugins/oauth/providers/def.ts b/packages/backend/server/src/plugins/oauth/providers/def.ts index 8258e860d2..695eea7a07 100644 --- a/packages/backend/server/src/plugins/oauth/providers/def.ts +++ b/packages/backend/server/src/plugins/oauth/providers/def.ts @@ -84,8 +84,8 @@ export abstract class OAuthProvider { options?: { treatServerErrorAsInvalid?: boolean } ) { const response = await fetch(url, { - headers: { Accept: 'application/json', ...init?.headers }, ...init, + headers: { ...init?.headers, Accept: 'application/json' }, }); const body = await response.text();