Skip to content

Fix OAuth client_secret issues (#103) & Codex Business quotas (#101) - #104

Merged
diegosouzapw merged 1 commit into
mainfrom
fix-issues-101-103
Feb 21, 2026
Merged

diegosouzapw merged 1 commit into
mainfrom
fix-issues-101-103

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Fixes #103, Fixes #101

Copilot AI review requested due to automatic review settings February 21, 2026 21:25
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@github-actions

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @diegosouzapw, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves two distinct issues: one related to the flexible handling of OAuth client_secret parameters across various providers, and another concerning the accurate retrieval and display of Codex usage quotas for business-tier accounts. The changes ensure that OAuth integrations are more robust and that business users receive correct quota information.

Highlights

  • OAuth Client Secret Handling: The client_secret parameter in OAuth token exchange requests for antigravity, gemini, and iflow providers is now conditionally included. This addresses issues where some OAuth flows might not require or expect a client_secret, preventing potential errors.
  • Codex Business Quotas: The system now correctly fetches and applies business quotas for Codex usage. This involves dynamically retrieving the chatgpt-account-id for business accounts and updating the plan tier normalization to recognize 'BIZ' plan types.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • open-sse/services/usage.ts
    • Implemented dynamic fetching of ChatGPT account IDs to support business quotas for Codex usage.
  • src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx
    • Expanded business plan recognition in normalizePlanTier to include 'BIZ' type.
  • src/lib/oauth/providers/antigravity.ts
    • Made client_secret optional in the antigravity OAuth token exchange request body.
  • src/lib/oauth/providers/gemini.ts
    • Made client_secret optional in the gemini OAuth token exchange request body.
  • src/lib/oauth/providers/iflow.ts
    • Made client_secret optional in both the Basic Authorization header and the request body for iflow OAuth token exchange.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

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

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.

Code Review

The pull request introduces improvements for handling OAuth client secrets by making them conditional, which enhances flexibility and robustness for different OAuth provider configurations. It also adds logic to fetch and utilize ChatGPT account IDs for Codex usage tracking, including support for 'biz' plan types. The changes are generally well-implemented and address the stated issues.

try {
let accountId = null;
try {
const accountsRes = await fetch("https://chatgpt.com/backend-api/accounts/check/v4", {

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.

medium

The URL for fetching ChatGPT accounts is hardcoded here. It would be more maintainable to define this URL as a constant, similar to CODEX_CONFIG.usageUrl, to centralize configuration and make it easier to update if the endpoint changes in the future.

Suggested change
const accountsRes = await fetch("https://chatgpt.com/backend-api/accounts/check/v4", {
const accountsRes = await fetch(CODEX_CONFIG.accountsCheckUrl || "https://chatgpt.com/backend-api/accounts/check/v4", {

Copilot AI left a comment

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.

Pull request overview

This PR addresses OAuth token exchange failures when client_secret is missing/empty (notably in remote server mode) and improves OpenAI Codex Business quota detection/display by selecting the correct workspace/account context.

Changes:

  • Make OAuth token exchange for iFlow/Gemini/Antigravity omit client_secret (and iFlow Basic auth) when the secret is not configured.
  • Improve plan-tier normalization to recognize “biz” / “BIZ” as Business.
  • For Codex usage, attempt to resolve a non-free (preferably biz) workspace account id and pass it via chatgpt-account-id to fetch correct quotas.

Reviewed changes

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

Show a summary per file
File Description
src/lib/oauth/providers/iflow.ts Conditionalizes Basic auth header and client_secret body param to avoid invalid credentials when unset.
src/lib/oauth/providers/gemini.ts Avoids sending an empty client_secret during token exchange.
src/lib/oauth/providers/antigravity.ts Avoids sending an empty client_secret during token exchange.
src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx Treats “BIZ” plan strings as Business tier for UI labeling/filtering.
open-sse/services/usage.ts Adds Codex workspace discovery and sends chatgpt-account-id header to retrieve correct quota data for Business accounts.

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

const accountsArray = Object.values(accountsData.accounts) as any[];
const targetWorkspace =
accountsArray.find((a) => a.account?.plan_type === "biz") ||
accountsArray.find((a) => a.account?.plan_type !== "free") ||

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

In the workspace selection, accountsArray.find((a) => a.account?.plan_type !== "free") will also match entries where plan_type is undefined/missing (because undefined !== "free" is true), which can pick an arbitrary workspace/accountId and still produce incorrect quota results. Consider tightening this predicate to require a defined plan_type (e.g., a.account?.plan_type && a.account.plan_type !== "free") or explicitly prefer known plan types in a allowlist.

Suggested change
accountsArray.find((a) => a.account?.plan_type !== "free") ||
accountsArray.find(
(a) => a.account?.plan_type && a.account.plan_type !== "free"
) ||

Copilot uses AI. Check for mistakes.
Comment on lines 487 to +513
async function getCodexUsage(accessToken) {
try {
let accountId = null;
try {
const accountsRes = await fetch("https://chatgpt.com/backend-api/accounts/check/v4", {
method: "GET",
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
},
});
if (accountsRes.ok) {
const accountsData = await accountsRes.json();
if (accountsData.accounts) {
const accountsArray = Object.values(accountsData.accounts) as any[];
const targetWorkspace =
accountsArray.find((a) => a.account?.plan_type === "biz") ||
accountsArray.find((a) => a.account?.plan_type !== "free") ||
accountsArray.find((a) => a.is_default) ||
accountsArray[0];
if (targetWorkspace && targetWorkspace.account?.id) {
accountId = targetWorkspace.account.id;
}
}
}
} catch (err) {
console.warn("Could not fetch ChatGPT accounts for quota:", err);

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

This adds an extra network round-trip (/backend-api/accounts/check/v4) on every Codex usage fetch. Since the dashboard refreshes periodically, this can noticeably increase latency and load (and may be rate-limited). Consider caching the resolved accountId for a short TTL (similar to the Antigravity subscription cache in this file) keyed by a truncated access token, and only refetching when the cache expires or the usage call indicates the wrong workspace.

Suggested change
async function getCodexUsage(accessToken) {
try {
let accountId = null;
try {
const accountsRes = await fetch("https://chatgpt.com/backend-api/accounts/check/v4", {
method: "GET",
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
},
});
if (accountsRes.ok) {
const accountsData = await accountsRes.json();
if (accountsData.accounts) {
const accountsArray = Object.values(accountsData.accounts) as any[];
const targetWorkspace =
accountsArray.find((a) => a.account?.plan_type === "biz") ||
accountsArray.find((a) => a.account?.plan_type !== "free") ||
accountsArray.find((a) => a.is_default) ||
accountsArray[0];
if (targetWorkspace && targetWorkspace.account?.id) {
accountId = targetWorkspace.account.id;
}
}
}
} catch (err) {
console.warn("Could not fetch ChatGPT accounts for quota:", err);
// Short-lived cache for Codex account IDs, keyed by truncated access token
type CodexAccountCacheEntry = {
accountId: string;
expiresAt: number;
};
const CODEX_ACCOUNT_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
const codexAccountCache = new Map<string, CodexAccountCacheEntry>();
function getCodexAccountCacheKey(accessToken: string): string | null {
if (typeof accessToken !== "string" || accessToken.length === 0) {
return null;
}
// Use a truncated token to avoid storing the full secret as a key
return accessToken.slice(0, 16);
}
async function getCodexUsage(accessToken) {
try {
const cacheKey = getCodexAccountCacheKey(accessToken);
let accountId: string | null = null;
// Try to use cached accountId if available and not expired
if (cacheKey) {
const cached = codexAccountCache.get(cacheKey);
if (cached && cached.expiresAt > Date.now()) {
accountId = cached.accountId;
}
}
// Only fetch accounts if we don't have a valid cached accountId
if (!accountId) {
try {
const accountsRes = await fetch("https://chatgpt.com/backend-api/accounts/check/v4", {
method: "GET",
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
},
});
if (accountsRes.ok) {
const accountsData = await accountsRes.json();
if (accountsData.accounts) {
const accountsArray = Object.values(accountsData.accounts) as any[];
const targetWorkspace =
accountsArray.find((a) => a.account?.plan_type === "biz") ||
accountsArray.find((a) => a.account?.plan_type !== "free") ||
accountsArray.find((a) => a.is_default) ||
accountsArray[0];
if (targetWorkspace && targetWorkspace.account?.id) {
accountId = targetWorkspace.account.id;
if (cacheKey) {
codexAccountCache.set(cacheKey, {
accountId,
expiresAt: Date.now() + CODEX_ACCOUNT_CACHE_TTL_MS,
});
}
}
}
}
} catch (err) {
console.warn("Could not fetch ChatGPT accounts for quota:", err);
}

Copilot uses AI. Check for mistakes.
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.

Issue: Token exchange failed: Bad client credentials Issue: Account type and quota information displayed incorrectly

2 participants