[Feat] Add xAI Grok subscription OAuth - #773
Conversation
Operators can connect SuperGrok / eligible X Premium+ via device-code OAuth from Settings and setup; the inference gateway prefers a refreshed OAuth bearer for xai/ models and falls back to XAI_API_KEY.
|
1 issue outstanding. See task
Reviewed a69e298 |
Assert disconnect deletes the encrypted secret and sandbox runtime env emits R_INFERENCE_GATEWAY_XAI without shipping tokens when only SuperGrok OAuth is connected.
Inject SuperGrok access tokens as XAI_API_KEY for non-gateway OpenCode (API-key shaped provider), and add refresh-failure, worker rebase, and command token-strip coverage.
Bring the feature branch up to date with the latest base branch.
Add Settings row coverage for OAuth-only, dual key+subscription, and errored reconnect, plus setup wizard Connect Grok subscription flow tests.
Keep PR branch current with latest develop before final review.
…alog poll cancel Prevent stale device-code poll loops from winning after cancel/reopen, and add missing db mock for SuperGrok OAuth checks so task-models unit tests pass. Note: commit signing skipped because 1Password agent refused operation in this session.
Register the current device code on start and gate token saves on it under a lock so a cancelled/restarted dialog cannot have an in-flight poll overwrite a newer subscription.
|
Addressed the outstanding review finding on Server-side fix in
Covered with unit tests for superseded codes and mid-flight restart races. |
Reserve a claim id under lock before calling xAI so a slower earlier start cannot overwrite a newer dialog's pending device code after its HTTP returns.
Take the same device-auth lock when disconnecting so a poll that already received tokens cannot re-save the subscription after the operator disconnects.
Take both device and refresh locks on disconnect so an in-flight token refresh cannot restore credentials. Keep connected on transient refresh failures and prefer a connected subscription over BYOK on the control plane, matching the gateway.
Dual-path xAI shares one catalog id. Removing the API key while a Grok subscription remains should strip only the key env vars, count both credentials for delete enablement, and close the setup dialog on provider switch.
|
Excited for this! Let me know if/when it’s ready for me to review. |
|
Hey @mrubens , just finished testing on my VM , it's ready, Grok 4.5 is magic the speed is 💯 |
Remove unused OpenCode auth helpers that could ship refresh tokens, stop device-code polling when the code expires, and treat slow_down intervals as replacements. Apply the same poll-interval/expiry fixes to Copilot.
|
Hi @pridemusvaire, I took a quick look and had a couple suggestions to make this more consistent with the other subscription providers:
Thanks! |
Hey @mrubens , sure let me update, thanks 🙏 |
Address maintainer review: SuperGrok is now catalog id xai-subscription (oauth), separate from the xAI API-key provider, matching ChatGPT vs OpenAI. Serialize device-code persist with refresh locks, and surface SuperGrok usage via the unofficial Grok billing proxy when available.
Include `xai` in connected provider ids when SuperGrok is connected so subscription-only deploys keep xai/* catalog models. Enable the setup status query for xai-subscription, update docs/usage copy, and add a refresh CAS test.
Stop returning refresh tokens from getFreshXaiAccessToken, run IdP refresh HTTP outside the advisory lock with CAS write-back, and cover the Grok usage parser/fetcher with unit tests.
The secret-executor harness only covers simple select chains and broke when fetchXaiSubscriptionUsage loaded tokens through the full xAI refresh path.
The add-provider OAuth dialog defaulted non-Copilot providers to ChatGPT copy and button label, so selecting xAI Grok subscription was wrong.
Onboarding dual-path only checked the xai-subscription id, so selecting xAI never showed Connect Grok subscription or SuperGrok connected state.
cli-chat-proxy returns config.creditUsagePercent, productUsage, and
{val} wrappers, not the synthetic included_usage shape, so SuperGrok
connected with no usage line. Accept the live shape and remaining-only
credit rows in the settings bar.
|
hey @mrubens , sorted now thanks, I will submit another PR to add the Z.AI usage bar too |
…cription-oauth # Conflicts: # apps/web/src/components/settings/InferenceProviderSection.test.tsx # apps/web/src/trpc/commands/subscription-usage/index.ts # packages/db/src/lib/__tests__/subscription-provider-usage.test.ts # packages/db/src/lib/subscription-provider-usage.ts # packages/types/src/subscription-provider-usage.ts
Mirror the ChatGPT/OpenAI display relationship for xAI: `xai/` models group under the Grok subscription entry when it is the only xAI-facing connection and stay under the native xAI group when an API key is also connected. Pass the subscription/API-key state through both groupModelsByDisplayProvider callers (launch model select and Models settings role selectors) via getLaunchTaskModelsCommand and the connected-provider list.
Paid Grok plans share a single weekly pool across products, so the per-product breakdown renders as duplicate-looking bars whenever one product dominates (an API-only deployment shows "Api: N%" identical to the aggregate). Show only the aggregate pool percent and leave the breakdown to grok.com's usage page. Show the on-demand credit balance only when it is positive: that is the state where tasks continue on metered spend past the pool, while "Credits: 0 left" is the common idle state and reads as an error.
|
Hi @pridemusvaire — thanks for the updates, the separate provider + JSON billing endpoints came out great. I pushed three commits to your branch to keep things moving (hope that's okay, maintainer edits were enabled):
Everything's green locally and the PR shows mergeable again. I think this is ready to land once CI agrees — thanks again for driving this! |
The regex entry alone covers the UUID-shaped public client id; the paths entry additionally exempted the whole file from every rule, which would silently allow a real secret added there later.
|
hey @mrubens , sounds good , thanks for the review |
Summary
Adds SuperGrok / eligible X Premium+ as a first-class inference path in Roomote, next to the existing xAI API key (BYOK) path.
Operators can connect a Grok subscription with device-code OAuth, run
xai/*models on that subscription, see usage bars in Models settings, and still keep or remove a separateXAI_API_KEYwithout breaking the other path.What operators get
xai-subscription, OAuth). Connect / reconnect / disconnect. Usage bars under the row when billing data is available. Existing xAI row stays API-key only (XAI_API_KEY).xai/*models work with SuperGrok alone, API key alone, or both. When both are configured, subscription is preferred.Connect copy is provider-specific (Connect Grok subscription, not ChatGPT).
How it works
Catalog split (same pattern as OpenAI API key vs ChatGPT subscription)
xaiXAI_API_KEYxai-subscriptionSuperGrok still serves
xai/*model ids. When only the subscription is connected, setup/auto-add treat thexaicatalog surface as available so models stay listed. Deleting the API key while SuperGrok remains strips only key env vars and does not removexai/*models.Control plane
XAI_SUBSCRIPTION_OAUTHsecret.getFreshXaiAccessTokennever return refresh tokens to callers.Inference
authStrategy: 'xai-oauth': OAuth bearer first, thenXAI_API_KEY, fail closed if neither.R_INFERENCE_GATEWAY_XAIso OpenCode rebasesxaionto the gateway without shipping tokens into the sandbox.Usage bars
cli-chat-proxy.grok.com).format=creditspayload (config.creditUsagePercent,productUsage,{ val }wrappers, period end) plus older synthetic shapes.Hardening included (review + live test follow-ups)
xai-subscription.Test plan
xaiSubscriptionConnected/xaiApiKeyConnected; SuperGrok contributesxaifor models when key is absentroomote.fleetcast.co)