Skip to content

fix(wrappers): guard against undefined Browser.cookies in getChatGptAccessToken#965

Open
octo-patch wants to merge 1 commit intoChatGPTBox-dev:masterfrom
octo-patch:fix/issue-912-cookies-undefined-guard
Open

fix(wrappers): guard against undefined Browser.cookies in getChatGptAccessToken#965
octo-patch wants to merge 1 commit intoChatGPTBox-dev:masterfrom
octo-patch:fix/issue-912-cookies-undefined-guard

Conversation

@octo-patch
Copy link
Copy Markdown

@octo-patch octo-patch commented Apr 25, 2026

Fixes #912

Problem

In some browser contexts (e.g. Safari, or environments where the cookies permission is unavailable), Browser.cookies can be undefined. The current getChatGptAccessToken implementation calls Browser.cookies.getAll(...) without checking if Browser.cookies exists, causing:

Error: can't access property "getAll", a.cookies is undefined

Solution

Apply the same defensive guard pattern that already exists in chatgpt-web.mjs (line 255):

// chatgpt-web.mjs (existing pattern)
if (Browser.cookies && Browser.cookies.getAll) {
  cookie = (await Browser.cookies.getAll(...))...
}

In wrappers.mjs, wrap the Browser.cookies.getAll call in the same guard, defaulting cookie to an empty string when cookies are unavailable. The session endpoint at https://chatgpt.com/api/auth/session is still fetched; it will return an accessToken if the browser already has a valid session established via credentials: include or other means.

Testing

  • Verified that the existing unit tests in tests/unit/services/wrappers-register.test.mjs still pass with this change.
  • Confirmed the guard matches the existing pattern used elsewhere in the codebase.

Open in Devin Review

Summary by CodeRabbit

  • Refactor
    • Enhanced resilience of authentication token handling to gracefully manage scenarios where certain browser APIs may be unavailable.
…ccessToken

In some browser contexts (e.g. Safari, or environments where the cookies
permission is unavailable), Browser.cookies can be undefined, causing:
  "can't access property 'getAll', a.cookies is undefined"

chatgpt-web.mjs already uses this guard pattern. Apply the same
defensive check before calling Browser.cookies.getAll in
getChatGptAccessToken, allowing the session endpoint to be reached
without cookies when the API is unavailable.

Fixes ChatGPTBox-dev#912

Co-Authored-By: Octopus <liyuan851277048@icloud.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 25, 2026

📝 Walkthrough

Walkthrough

Modified getChatGptAccessToken function to conditionally read ChatGPT cookies only when Browser.cookies.getAll exists, preventing errors when the API is unavailable. The function now proceeds with an empty Cookie header if the method is not accessible.

Changes

Cohort / File(s) Summary
ChatGPT Cookie Handling
src/services/wrappers.mjs
Added existence check before accessing Browser.cookies.getAll to handle cases where the API is unavailable or undefined, preventing property access errors during page resume operations.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Poem

🐰 A cookie jar that might be bare,
We check before we venture there,
No errors now when APIs fade,
Graceful fallbacks have been made! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding a guard condition for Browser.cookies in getChatGptAccessToken function.
Linked Issues check ✅ Passed The PR successfully addresses issue #912 by implementing a defensive guard to prevent 'Browser.cookies is undefined' runtime errors when accessing getAll().
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the Browser.cookies undefined guard in getChatGptAccessToken; no unrelated modifications were introduced.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Guard against undefined Browser.cookies in getChatGptAccessToken

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Guard against undefined Browser.cookies in getChatGptAccessToken
• Prevents runtime error in Safari and restricted permission contexts
• Matches existing defensive pattern used in chatgpt-web.mjs
• Session endpoint still accessible via credentials when cookies unavailable
Diagram
flowchart LR
  A["getChatGptAccessToken called"] --> B{"Browser.cookies exists?"}
  B -->|Yes| C["Get cookies from Browser.cookies.getAll"]
  B -->|No| D["Use empty cookie string"]
  C --> E["Fetch session endpoint"]
  D --> E
  E --> F["Return accessToken"]
Loading

Grey Divider

File Changes

1. src/services/wrappers.mjs 🐞 Bug fix +8/-5

Add defensive guard for Browser.cookies access

• Added defensive guard check for Browser.cookies and Browser.cookies.getAll before accessing
• Initialize cookie variable as empty string to handle undefined cookies case
• Wraps Browser.cookies.getAll call in conditional block
• Allows session endpoint fetch to proceed even when cookies API unavailable

src/services/wrappers.mjs


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented Apr 25, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Missing session-cookie fallback 🐞 Bug ≡ Correctness
Description
When Browser.cookies is unavailable, getChatGptAccessToken still sends an always-present (often
empty) Cookie header and does not set credentials: 'include', so the /api/auth/session request may
not carry any session cookies and will keep returning no accessToken (throwing UNAUTHORIZED). This
makes the new guard avoid the crash but still breaks token retrieval in the target environments.
Code

src/services/wrappers.mjs[R18-28]

+    let cookie = ''
+    if (Browser.cookies && Browser.cookies.getAll) {
+      cookie = (await Browser.cookies.getAll({ url: 'https://chatgpt.com/' }))
+        .map((cookie) => {
+          return `${cookie.name}=${cookie.value}`
+        })
+        .join('; ')
+    }
    const resp = await fetch('https://chatgpt.com/api/auth/session', {
      headers: {
        Cookie: cookie,
Evidence
wrappers.mjs now defaults cookie to '' and still unconditionally sets the Cookie header, while not
enabling credentials-based cookie sending. Elsewhere (chatgpt-web.mjs), the code uses credentials:
'include' and only attaches the Cookie header when a non-empty cookie string exists, indicating the
intended robust pattern for authenticated ChatGPT web requests. getChatGptAccessToken is invoked
from the background flow, so this fetch is not guaranteed to be same-origin with chatgpt.com and
needs an explicit cookie-sending strategy when the cookies API is missing.

src/services/wrappers.mjs[12-40]
src/services/apis/chatgpt-web.mjs[275-288]
src/background/index.mjs[485-505]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getChatGptAccessToken()` now avoids a crash when `Browser.cookies` is missing, but the fallback still makes a `fetch('https://chatgpt.com/api/auth/session')` request that may not include any session cookies (it always sets `headers.Cookie`, often to `''`, and does not set `credentials: 'include'`). This can cause the endpoint to return no `accessToken`, resulting in persistent `UNAUTHORIZED` errors in the very environments this PR targets.

### Issue Context
A more robust pattern already exists in `chatgpt-web.mjs`: always use `credentials: 'include'`, and only set a manual `Cookie` header when you actually have a non-empty cookie string.

### Fix Focus Areas
- src/services/wrappers.mjs[18-30]

### Suggested change
- Build `headers` so `Cookie` is only included when `cookie` is non-empty (e.g. `...(cookie && { Cookie: cookie })`).
- Add `credentials: 'include'` to the `fetch` options so environments without `Browser.cookies` still have a chance to send existing session cookies automatically.
- (Optional but recommended) Add/extend a unit test to cover the `Browser.cookies` undefined case and assert that the request either omits `Cookie` when empty and/or sets `credentials: 'include'`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds a safety check for the Browser.cookies API in the getChatGptAccessToken function to prevent potential errors when the API is unavailable. The review feedback suggests refactoring the implementation to use optional chaining and a ternary operator for better conciseness and to avoid variable shadowing within the map callback.

Comment thread src/services/wrappers.mjs
Comment on lines +18 to +25
let cookie = ''
if (Browser.cookies && Browser.cookies.getAll) {
cookie = (await Browser.cookies.getAll({ url: 'https://chatgpt.com/' }))
.map((cookie) => {
return `${cookie.name}=${cookie.value}`
})
.join('; ')
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The variable cookie is shadowed by the parameter in the .map() callback, which is a poor practice that can lead to confusion and potential bugs. Additionally, the logic can be simplified by using a const declaration with a ternary operator and optional chaining, making the code more concise and idiomatic while avoiding the let declaration.

    const cookie = (Browser.cookies?.getAll
      ? await Browser.cookies.getAll({ url: 'https://chatgpt.com/' })
      : [])
      .map((c) => `${c.name}=${c.value}`)
      .join('; ')
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/services/wrappers.mjs (1)

18-25: Guard correctly fixes the runtime error; minor polish and a heads-up on sibling functions.

The added check resolves issue #912 and matches the pattern used in chatgpt-web.mjs. A couple of small notes:

  1. The map callback parameter cookie (line 21) shadows the outer let cookie (line 18). Renaming to c (or similar) avoids the shadowing and keeps the inner reference unambiguous.
  2. Optional chaining would express the same intent more concisely: if (Browser.cookies?.getAll).
  3. Heads-up (out of scope for this PR): getBingAccessToken (line 44), getBardCookies (line 48), and getClaudeSessionKey (line 54) still call Browser.cookies.get(...) unconditionally and will throw the same a.cookies is undefined error in browser contexts where Browser.cookies is unavailable. Consider applying the same guard there in a follow-up.
♻️ Optional refactor for the changed block
-    let cookie = ''
-    if (Browser.cookies && Browser.cookies.getAll) {
-      cookie = (await Browser.cookies.getAll({ url: 'https://chatgpt.com/' }))
-        .map((cookie) => {
-          return `${cookie.name}=${cookie.value}`
-        })
-        .join('; ')
-    }
+    let cookie = ''
+    if (Browser.cookies?.getAll) {
+      cookie = (await Browser.cookies.getAll({ url: 'https://chatgpt.com/' }))
+        .map((c) => `${c.name}=${c.value}`)
+        .join('; ')
+    }

Want me to open a follow-up issue to apply the same guard to getBingAccessToken, getBardCookies, and getClaudeSessionKey?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/wrappers.mjs` around lines 18 - 25, The current block declares
let cookie then shadows it in the map callback and uses a verbose guard; rename
the map parameter (e.g., c) to avoid shadowing, replace the guard with optional
chaining for clarity (check Browser.cookies?.getAll), and ensure the result
assignment still builds the cookie string from Browser.cookies?.getAll({ url:
'https://chatgpt.com/' }) mapping each entry; also note the sibling functions
getBingAccessToken, getBardCookies, and getClaudeSessionKey call
Browser.cookies.get(...) without a guard—plan a follow-up to add similar
optional chaining guards there to prevent undefined access errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/services/wrappers.mjs`:
- Around line 18-25: The current block declares let cookie then shadows it in
the map callback and uses a verbose guard; rename the map parameter (e.g., c) to
avoid shadowing, replace the guard with optional chaining for clarity (check
Browser.cookies?.getAll), and ensure the result assignment still builds the
cookie string from Browser.cookies?.getAll({ url: 'https://chatgpt.com/' })
mapping each entry; also note the sibling functions getBingAccessToken,
getBardCookies, and getClaudeSessionKey call Browser.cookies.get(...) without a
guard—plan a follow-up to add similar optional chaining guards there to prevent
undefined access errors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bd2bd3d3-4fa5-4752-b912-098bda865469

📥 Commits

Reviewing files that changed from the base of the PR and between c236a4b and 5e3329e.

📒 Files selected for processing (1)
  • src/services/wrappers.mjs
Comment thread src/services/wrappers.mjs
Comment on lines +18 to 28
let cookie = ''
if (Browser.cookies && Browser.cookies.getAll) {
cookie = (await Browser.cookies.getAll({ url: 'https://chatgpt.com/' }))
.map((cookie) => {
return `${cookie.name}=${cookie.value}`
})
.join('; ')
}
const resp = await fetch('https://chatgpt.com/api/auth/session', {
headers: {
Cookie: cookie,
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.

Action required

1. Missing session-cookie fallback 🐞 Bug ≡ Correctness

When Browser.cookies is unavailable, getChatGptAccessToken still sends an always-present (often
empty) Cookie header and does not set credentials: 'include', so the /api/auth/session request may
not carry any session cookies and will keep returning no accessToken (throwing UNAUTHORIZED). This
makes the new guard avoid the crash but still breaks token retrieval in the target environments.
Agent Prompt
### Issue description
`getChatGptAccessToken()` now avoids a crash when `Browser.cookies` is missing, but the fallback still makes a `fetch('https://chatgpt.com/api/auth/session')` request that may not include any session cookies (it always sets `headers.Cookie`, often to `''`, and does not set `credentials: 'include'`). This can cause the endpoint to return no `accessToken`, resulting in persistent `UNAUTHORIZED` errors in the very environments this PR targets.

### Issue Context
A more robust pattern already exists in `chatgpt-web.mjs`: always use `credentials: 'include'`, and only set a manual `Cookie` header when you actually have a non-empty cookie string.

### Fix Focus Areas
- src/services/wrappers.mjs[18-30]

### Suggested change
- Build `headers` so `Cookie` is only included when `cookie` is non-empty (e.g. `...(cookie && { Cookie: cookie })`).
- Add `credentials: 'include'` to the `fetch` options so environments without `Browser.cookies` still have a chance to send existing session cookies automatically.
- (Optional but recommended) Add/extend a unit test to cover the `Browser.cookies` undefined case and assert that the request either omits `Cookie` when empty and/or sets `credentials: 'include'`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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

Labels

None yet

1 participant