Skip to content

feat: add unified provider account authentication - #186

Merged
cnjack merged 5 commits into
mainfrom
codex/grok-unified-auth
Aug 10, 2026
Merged

feat: add unified provider account authentication#186
cnjack merged 5 commits into
mainfrom
codex/grok-unified-auth

Conversation

@cnjack

@cnjack cnjack commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • add unified managed-account authentication for ChatGPT/Codex OAuth, xAI/Grok OAuth, and GitHub Copilot while retaining API-key providers
  • integrate device login, multi-account selection, default-account management, reauthentication, removal, and logout into first-run setup and Settings → Providers
  • load each managed account's live model catalog in setup and Settings, persist explicitly enabled models, and refresh stale provider/vendor/protocol metadata on re-enable
  • show the last successful account-aware Provider catalog immediately on reopen, then revalidate in the background; transient failures preserve cached results and stale requests cannot overwrite a newer account/refresh
  • route managed models through provider-specific transports: Codex and xAI chat use Responses; Copilot selects Responses or Chat Completions from each model's advertised vendor
  • expose the official xAI grok-imagine-image and grok-imagine-image-quality models through the independent Image Model role with per-dispatch managed credentials
  • allow managed xAI Image Models through normal-mode tool discovery without requiring an API key, so selected Grok Imagine models expose generate_image
  • preserve encrypted Responses reasoning across tool turns and session replay, including cancellation/error hardening and parallel tool calls
  • document the POC, architecture, UI contract, configuration, model behavior, web endpoints, and current limitations

Security and lifecycle

  • managed tokens remain backend-only and are stored in an owner-only, atomically updated, file-locked account store
  • access tokens refresh per request with singleflight/CAS protection; missing or stale credentials fail closed
  • authentication, model-catalog, chat, and image clients do not follow redirects, bound response sizes, and validate production hosts
  • model-catalog errors do not return provider response bodies; account logins, tokens, device codes, and live payloads are not written to config or docs
  • the UI catalog cache contains model metadata only and is separated by Provider, auth method, selected/default account, and Base URL
  • cancel/logout is linearized against in-flight authorization commits, including multiple manager instances
  • provider bindings persist only the authentication method and account ID; no token is returned to the Web UI
  • managed xAI image generation pins the official endpoint/model allowlist and continues through the existing billable approval, quota, journal, artifact, and safe-download pipeline

Validation

  • go build ./...
  • go vet ./...
  • golangci-lint run --new-from-rev=origin/main ./...
  • go test ./... via the repository pre-push hook
  • go test -race ./internal/providerauth ./internal/providertools ./internal/imagegen ./internal/model ./internal/command ./internal/web -count=1
  • pnpm --dir web test (21 files / 103 tests)
  • pnpm --dir web typecheck
  • pnpm --dir web build
  • pnpm --dir site build
  • read-only live catalog smoke against authenticated xAI and GitHub Copilot accounts; verified xAI chat/image/video classification and Copilot model-specific vendor routing without printing credentials or issuing billable inference
  • browser QA for Settings → Providers at desktop, 720 px, and 480 px widths with no console errors or horizontal overflow

Manual verification still needed

  • billable chat/image inference was intentionally not run against personal subscription accounts
  • GitHub Enterprise Server is not supported in this first implementation
  • xAI video models are recognized but remain hidden until JCode has an asynchronous video-generation workflow
  • arbitrary custom image endpoints still require a separate API-key provider; only the pinned official xAI image profile can reuse managed OAuth

This PR remains draft until billable live inference smoke tests are explicitly approved and completed.

Summary by CodeRabbit

  • New Features

    • Added unified provider sign-in for ChatGPT/Codex, Grok, and GitHub Copilot, including device authorization and account management.
    • Added live, account-specific model catalogs and managed provider configuration in setup and Settings.
    • Added provider-backed image generation with Grok Imagine aspect-ratio and resolution controls.
    • Added durable generated-image artifacts and improved session continuity.
    • Added bottom-dock Ask User experience and capability-aware model routing.
  • Bug Fixes

    • Improved authentication, catalog caching, image availability, configuration persistence, and session replay reliability.
  • Documentation

    • Expanded setup, provider, security, image-generation, and account-authentication guidance.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 82ee1883-4bce-4e1b-9e85-3164d0cecc7a

📥 Commits

Reviewing files that changed from the base of the PR and between 73567b8 and 0bb1db3.

📒 Files selected for processing (95)
  • CHANGELOG.md
  • internal-doc/image-generation-architecture.md
  • internal-doc/provider-tools-image-generation-prd.md
  • internal-doc/provider-unified-auth-poc.md
  • internal-doc/provider-unified-auth-ui.md
  • internal-doc/provider-unified-auth.md
  • internal/agent/compaction.go
  • internal/agent/history.go
  • internal/command/image_generation.go
  • internal/command/image_generation_test.go
  • internal/command/interactive.go
  • internal/command/provider_runtime_verifier.go
  • internal/command/web_tool_overrides.go
  • internal/command/web_tool_overrides_test.go
  • internal/config/config.go
  • internal/config/provider_auth_test.go
  • internal/handler/acp.go
  • internal/handler/acp_test.go
  • internal/handler/handler.go
  • internal/handler/web_test.go
  • internal/imagegen/client.go
  • internal/imagegen/client_test.go
  • internal/imagegen/token_plan_multimodal.go
  • internal/model/chatmodel.go
  • internal/model/chatmodel_managed_auth_test.go
  • internal/model/managed_provider_registry_test.go
  • internal/model/provider_request.go
  • internal/model/provider_request_test.go
  • internal/model/registry.go
  • internal/model/responsemeta/opaque.go
  • internal/model/responses.go
  • internal/model/responses_convert.go
  • internal/model/responses_parse.go
  • internal/model/responses_test.go
  • internal/providerauth/codex.go
  • internal/providerauth/copilot.go
  • internal/providerauth/credential.go
  • internal/providerauth/filelock_unix.go
  • internal/providerauth/filelock_windows.go
  • internal/providerauth/http.go
  • internal/providerauth/jwt.go
  • internal/providerauth/manager.go
  • internal/providerauth/manager_test.go
  • internal/providerauth/models.go
  • internal/providerauth/models_test.go
  • internal/providerauth/store.go
  • internal/providerauth/types.go
  • internal/providerauth/xai.go
  • internal/providertools/manifest.go
  • internal/providertools/manifest_test.go
  • internal/runner/approval.go
  • internal/runner/approval_test.go
  • internal/runner/responses_continuity_test.go
  • internal/runner/runner.go
  • internal/session/history.go
  • internal/session/responses_continuity_test.go
  • internal/session/session.go
  • internal/team/manager.go
  • internal/tools/generate_image.go
  • internal/tools/generate_image_test.go
  • internal/tools/subagent.go
  • internal/web/models.go
  • internal/web/models_test.go
  • internal/web/provider_auth.go
  • internal/web/provider_auth_test.go
  • internal/web/providers.go
  • internal/web/server.go
  • internal/web/setup.go
  • packages/jcode-ui-core/CHANGELOG.md
  • packages/jcode-ui-core/src/types/index.ts
  • packages/jcode-ui/CHANGELOG.md
  • packages/jcode-ui/src/components/ApprovalBanner.test.tsx
  • packages/jcode-ui/src/components/ApprovalBanner.tsx
  • packages/jcode-ui/src/product/types.ts
  • site/docs/changelog.md
  • site/docs/configuration.md
  • site/docs/get-started.md
  • site/docs/overview/models.md
  • site/docs/web-interface.md
  • web/src/components/SettingsView.test.tsx
  • web/src/components/SettingsView.tsx
  • web/src/components/SetupView.test.tsx
  • web/src/components/SetupView.tsx
  • web/src/components/settings/ProviderAuthSection.test.tsx
  • web/src/components/settings/ProviderAuthSection.tsx
  • web/src/i18n/locales/en.ts
  • web/src/i18n/locales/ja.ts
  • web/src/i18n/locales/ko.ts
  • web/src/i18n/locales/zh-Hans.ts
  • web/src/i18n/locales/zh-Hant.ts
  • web/src/i18n/providerAuth.test.ts
  • web/src/lib/api.ts
  • web/src/lib/providerCatalogCache.ts
  • web/src/lib/providerIcons.ts
  • web/src/lib/types.ts

📝 Walkthrough

Walkthrough

This PR adds unified managed-provider authentication for Codex, xAI, and GitHub Copilot. It adds OAuth account storage, live model catalogs, protected transports, native xAI image controls, Responses continuity, provider setup APIs, and web authentication flows.

Changes

Unified managed-provider platform

Layer / File(s) Summary
Authentication contracts and account lifecycle
internal/providerauth/*, internal/config/*, internal/model/registry.go
Adds OAuth account types, device flows, secure persistence, credential refresh, provider bindings, and managed model catalogs.
Authenticated chat and Responses transports
internal/model/*
Adds managed credential injection, Copilot request classification, Responses API conversion, streaming, parsing, usage tracking, and bounded provider errors.
Provider configuration and live model routing
internal/web/providers.go, internal/web/models.go, internal/web/setup.go, internal/web/provider_auth.go
Adds managed provider validation, account-scoped catalogs, model persistence, authentication endpoints, and routing refresh.
Provider-native image generation
internal/imagegen/*, internal/tools/generate_image.go, internal/providertools/*, internal/command/*, internal/handler/*, packages/jcode-ui/*
Adds xAI OAuth image generation, native aspect-ratio and resolution controls, legacy-size normalization, capability routing, and approval display fields.
Responses session continuity
internal/model/responsemeta/*, internal/runner/*, internal/session/*, internal/team/*, internal/agent/*
Preserves bounded opaque Responses metadata across streaming, recording, reconstruction, compaction, and subagent requests.
Setup, settings, cache, and documentation
web/src/components/*, web/src/lib/*, web/src/i18n/*, site/docs/*, internal-doc/*
Adds setup and settings authentication flows, account management, catalog caching, localized strings, provider icons, and implementation documentation.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SettingsView
  participant ProviderAuthAPI
  participant ProviderAuthManager
  participant ProviderRuntime
  User->>SettingsView: Select managed authentication
  SettingsView->>ProviderAuthAPI: Start and poll device flow
  ProviderAuthAPI->>ProviderAuthManager: Resolve account credential
  ProviderAuthManager-->>ProviderAuthAPI: Return token and provider runtime
  ProviderAuthAPI-->>SettingsView: Return account status and model catalog
  SettingsView->>ProviderRuntime: Save binding and selected model
  ProviderRuntime->>ProviderAuthManager: Resolve credential per request
  ProviderRuntime-->>User: Generate chat or image response
Loading

Possibly related PRs

  • cnjack/jcode#118: Both changes update compaction and recorded history metadata.
  • cnjack/jcode#131: Both changes update provider and model management handlers.
  • cnjack/jcode#143: Both changes update provider model metadata and provider-agent rebuilding.
  • cnjack/jcode#145: Both changes update managed chat-model construction and provider-aware transport behavior.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/grok-unified-auth

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.

@jcode-cloud-app jcode-cloud-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

jcode review

Clean result. The unified provider account authentication PR (managed OAuth device flows for ChatGPT/Codex, xAI, and GitHub Copilot plus a Responses-API transport and encrypted-reasoning session continuity) was reviewed for correctness, security, reliability, and data loss. The credential store uses 0700/0600 permissions, atomic temp-file+rename+fsync replacement, and cross-process file locking (flock/LockFileEx). All upstream HTTP is bounded (64KiB OAuth, 16MiB responses, 2MiB SSE events), disables redirect following to prevent bearer/POST-body leakage, and validates header names/values and verification URIs (HTTPS, pinned host, no port/userinfo). Credential tokens are json:"-" and Authorization is applied last so provider config cannot override them. Device-flow generation guards prevent a Start in flight during Logout from restoring accounts; commitMu linearizes commit vs cancel. Session persistence retains only canonical encrypted reasoning items (cleartext reasoning is never written) and reconstruction drops orphan opaque-only turns while preserving continuation data on tool-only turns. Ran go build, go vet, and go test on internal/providerauth, internal/model (incl. responsemeta), internal/session, internal/runner, internal/web, internal/config — all pass. No defects meeting the 80% confidence threshold were identified.

0 findings

Checks performed
  • git diff base..head for internal/providerauth/*.go (manager, store, credential, codex, copilot, xai, http, jwt, types, filelock)
  • git diff base..head for internal/model (chatmodel, responses, responses_parse, responses_convert, provider_request, registry) and responsemeta/opaque.go
  • git diff base..head for internal/runner/runner.go and internal/session/{session,history}.go continuity changes
  • git diff base..head for internal/web/{provider_auth,providers,server,setup}.go and internal/config/config.go
  • Inspected ReconstructState/dropOrphanOpaqueAssistantMessages/RecordAssistantMessage for opaque-reasoning retention and orphan-drop correctness across both journal orderings
  • Inspected Start/Logout generation race, commitFlowAccount/cancelPending commitMu linearizability, per-account refreshLocks
  • Inspected mergeEndpoints parallel-array field ordering (13 endpoints matched)
  • Inspected credential isolation: Credential.Token json:"-", Authorization applied last, no redirect following in cloneHTTPClient/cloneResponsesHTTPClient/managedNoRedirectClient
  • Inspected validateVerificationURI/validateManagedAuthEndpoint/validCopilotRuntime host pinning
  • go generate ./internal/model/... then go build ./internal/providerauth/... ./internal/model/... ./internal/session/... ./internal/runner/... ./internal/web/... (pass)
  • go vet ./internal/providerauth/... ./internal/model/... ./internal/session/... ./internal/runner/... (pass)
  • go test ./internal/providerauth/... ./internal/model/... ./internal/session/... ./internal/runner/... ./internal/web/... ./internal/config/... (all pass)

jcode posts a non-blocking COMMENT review. Merge decisions remain with your team.

@jcode-cloud-app jcode-cloud-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

jcode review

Clean review. This PR adds unified managed-provider account authentication (ChatGPT/Codex, xAI/Grok, GitHub Copilot device flows) plus a Responses-API transport with encrypted-reasoning continuation. The credential model is sound: durable refresh tokens are stored owner-only (0700/0600) outside config.json via atomic fsync+rename writes guarded by cross-process file locks; short-lived access tokens are memory-only; refresh is singleflight per account; logout invalidation uses a durable generation epoch that flows must recheck before committing; managed runtimes block redirects (ErrUseLastResponse) so a bearer token/POST body cannot follow a redirect; verification URIs and discovery endpoints are pinned to exact hosts/scheme/port; Copilot runtime endpoints are restricted to *.githubcopilot.com; public Flow/Account/Status/Credential types exclude secrets (Credential.Token is json:"-"); the web API never accepts or returns tokens; switching a provider to managed auth strips dormant api_key/base_url/headers/protocol/image_endpoint. Session replay persists only canonical encrypted reasoning items (cleartext reasoning and arbitrary Extra are never written), bounds them, and drops orphan reasoning-only entries; reconstruction correctly re-merges tool calls into the preceding assistant message so continuation items are replayed. Existing API-key provider behavior and legacy session files are preserved (Auth/OpaqueResponseItems are additive omitempty fields). I generated the registry, created the embed stub, built all changed packages, ran go vet (clean), and ran the providerauth/model/runner/session/web/agent/team/tools tests — all pass. No defect met the 80% confidence threshold.

0 findings

Checks performed
  • git diff base..head across 63 changed files; reviewed providerauth/{manager,store,credential,http,jwt,codex,xai,copilot,types,filelock_*}.go
  • Reviewed model/{chatmodel,provider_request,responses,responses_parse,responses_convert,registry,responsemeta/opaque}.go diffs
  • Reviewed runner.go assistant recording, session.go RecordAssistantMessage, history.go ReconstructState opaque-item replay
  • Reviewed web/{provider_auth,providers,setup,server}.go for token leakage, binding validation, field-stripping on managed switch
  • Verified cloneHTTPClient/responses transport set CheckRedirect=ErrUseLastResponse for managed/OAuth paths
  • Verified validateVerificationURI/validateManagedAuthEndpoint pin scheme/host/port; xAI accounts.x.ai fix in head commit
  • Verified credential resolution singleflight + CAS secret rotation + requires_reauth fail-closed paths
  • Generated registry_generated.go (go generate ./internal/model/...) and stub internal/web/dist/index.html
  • go build ./internal/{providerauth,model,runner,session,web,command,agent,team,tools}/... — exit 0
  • go vet on changed packages — exit 0
  • go test ./internal/providerauth/... ./internal/model/... ./internal/session/... ./internal/runner/... ./internal/web/... — all pass

jcode posts a non-blocking COMMENT review. Merge decisions remain with your team.

@jcode-cloud-app jcode-cloud-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

jcode review

Clean result. This PR adds unified managed provider authentication (ChatGPT/Codex, xAI, GitHub Copilot OAuth) plus a Responses API transport and encrypted-reasoning session continuation. I reviewed the OAuth drivers, the owner-only secret store, the credential resolution path, the Responses SSE/JSON parser, the web auth/provider handlers, the runner + session recording of opaque reasoning, and the image-generation managed-credential wiring. The build compiles, go vet is clean, and the full test suites for internal/providerauth, internal/model (incl. responsemeta), internal/web, internal/session, internal/runner, internal/command, internal/imagegen, and internal/providertools pass, including the race detector for providerauth. Security invariants hold: durable secrets stay in a 0600 file and are never serialized (Credential.Token has json:"-"), public projections omit tokens, managed requests disable redirects and bound response bodies, verification/discovery URIs are pinned to expected HTTPS hosts, bindings fail closed when accounts are removed/expired, and the store uses atomic temp-file+fsync+rename under an advisory lock with a logout generation epoch that prevents in-flight flows from restoring deleted accounts. The opaque-reasoning path only ever persists canonical encrypted items (cleartext summary/content is stripped) and drops orphan reasoning-only entries on both record and replay. No verified defects introduced by this PR.

0 findings

Checks performed
  • git diff 73567b8..0eeda9e --stat and read full diff for internal/providerauth, internal/model, internal/web, internal/session, internal/runner
  • Read internal/providerauth/{manager,store,credential,codex,xai,copilot,http,jwt,types,models}.go in full
  • Read internal/model/{chatmodel.go,responses.go,responses_parse.go,responses_convert.go,provider_request.go,registry.go} and responsemeta/opaque.go
  • Read internal/web/{provider_auth.go,providers.go,setup.go,server.go} and provider_auth_test.go
  • Read internal/session/{history.go,session.go} changes and responses_continuity_test.go
  • go build ./internal/providerauth/... ./internal/model/... ./internal/web/... ./internal/session/... ./internal/runner/... ./internal/command/... ./internal/imagegen/... (clean)
  • go vet on all affected packages (clean, no diagnostics)
  • go test -count=1 on providerauth, model, model/responsemeta, web, session, runner, command, imagegen, providertools, config (all ok)
  • go test -race -count=1 ./internal/providerauth/... (ok, no data races)
  • Verified credential fail-closed paths: managedCredential BaseURL/Protocol drift, account removal invalidation, empty-token guard
  • Verified opaque reasoning: CanonicalReasoningItem strips cleartext; RecordAssistantMessage drops orphan items; dropOrphanOpaqueAssistantMessages on replay
  • Verified web binding validation: three-state auth_binding, managed providers clear api_key/base_url/headers/image_endpoint

jcode posts a non-blocking COMMENT review. Merge decisions remain with your team.

@jcode-cloud-app jcode-cloud-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

jcode review

Clean review. This large PR adds unified managed provider authentication (ChatGPT/Codex OAuth, xAI OAuth, GitHub Copilot device flows), a new OpenAI Responses API transport with SSE parsing, and encrypted-reasoning session continuity. The security-critical providerauth package isolates bearer/refresh tokens (Credential.Token uses json:"-"), disables HTTP redirects on all credential-bearing clients, validates verification URIs against pinned hosts (scheme/port/userinfo), validates header names and rejects CRLF injection, bounds every upstream response (64KiB OAuth, 1MiB catalogs, 2MiB SSE events, 16/2MiB opaque items), and hardens the secret store (0700 dir, 0600 files, atomic rename + fsync + flock). Concurrency is careful: durable logout epochs prevent stale cross-process flow commits, commit/cancel linearizability via commitMu, and double-checked locking on token refresh. Cleartext reasoning is never persisted; only bounded canonical encrypted items are retained and only when an assistant turn has content/tool calls. I verified go build ./..., go vet, the full test suite for all changed packages, and the race detector on providerauth/model/runner/session all pass. No defect meets the 80% confidence threshold.

0 findings

Checks performed
  • git diff base..head across all 78 changed files
  • Read internal/providerauth/{manager,store,credential,codex,xai,copilot,jwt,http,models,types}.go in full
  • Read internal/model/{chatmodel,responses,responses_parse,responses_convert,provider_request}.go and responsemeta/opaque.go
  • Read internal/web/{provider_auth,providers,server,setup,models}.go diff
  • Read internal/runner/runner.go streaming/replay diff and internal/session/{session,history}.go
  • go build ./... (with generated registry + dist stub) — PASS
  • go vet ./internal/providerauth/... ./internal/model/... ./internal/web/... ./internal/runner/... ./internal/session/... — clean
  • go test for all changed packages — PASS
  • go test -race on providerauth, model, runner, session — PASS
  • Verified token isolation: Credential.Token json:"-", Flow/Account/Status exclude secrets, ResponsesAPIError excludes bodies/headers
  • Verified logout generation-epoch commit guard and commitMu cancel linearizability in manager.go

jcode posts a non-blocking COMMENT review. Merge decisions remain with your team.

@jcode-cloud-app jcode-cloud-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

jcode review

Large unified provider-auth feature (OAuth device flows for Codex/xAI/Copilot, Responses API transport, managed model catalogs, xAI image generation). Security posture is strong: 0600 secret store with atomic rename+fsync, file locks, HTTPS-only verification-URI allowlisting, bounded upstream responses, CRLF/header validation, no token logging, and correct linearizable logout/commit concurrency via generation epochs. One verifiable reliability defect: the web layer caches the managed-auth manager initialization error permanently, disabling provider login/catalog until restart even after the underlying cause is fixed.

1 finding

Checks performed
  • Read internal/providerauth/{store,manager,credential,codex,copilot,xai,http,jwt,filelock_unix,filelock_windows,models,types}.go
  • Read internal/model/{chatmodel,responses,responses_parse,responses_convert,provider_request}.go and responsemeta/opaque.go
  • Read internal/web/{provider_auth,server,providers,setup,models}.go
  • Read internal/providertools/manifest.go and internal/imagegen/client.go
  • Read internal/tools/generate_image.go, internal/runner/runner.go, internal/session/{session,history}.go
  • Read internal/command/{image_generation,provider_runtime_verifier,web_tool_overrides,interactive}.go
  • Diff inspected for config.go, handler.go, team/manager.go, tools/subagent.go, approval.go
  • Verified providerauth.Default (manager.go:104-107) does not cache errors while web layer does (provider_auth.go:109)
  • Confirmed no code resets s.providerAuthErr (grep providerAuth/providerAuthErr assignments)
  • Reviewed frontend types.ts/api.ts for token exposure (none found)
  • Attempted go build (no network/module cache available; static review only)

jcode posts a non-blocking COMMENT review. Merge decisions remain with your team.

Comment on lines +109 to +114
if s.providerAuth != nil || s.providerAuthErr != nil {
return s.providerAuth, s.providerAuthErr
}
s.providerAuth, s.providerAuthErr = providerauth.Default(config.ConfigDir())
return s.providerAuth, s.providerAuthErr
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 · Provider-auth manager init error is cached permanently, blocking recovery without restart

providerAuthService caches both the resolved service AND any initialization error in s.providerAuth/s.providerAuthErr and returns the cached values on every subsequent call once either is non-nil. The underlying providerauth.Default (manager.go:93) intentionally does NOT cache errors — it only caches successful managers so a later call can retry after a transient NewManager failure (e.g. a momentarily unwritable/unavailable config dir during secureDirectory, a chmod race, or a corrupted/Hand-edited provider-auth.json that the user later repairs). The web layer defeats that retry: once providerauth.Default returns an error once, s.providerAuthErr stays set for the lifetime of the Server process, so every /api/provider-auth/* endpoint, the managed live-model catalog browse (handleProviderCatalog -> service.Models), and setup model listing (handleSetupProviderModels) keep returning HTTP 500 with the stale error even after the root cause is resolved. There is no code path that resets providerAuthErr (grep confirms it is only assigned here). Impact: a user who hits a one-time init failure (most plausibly a corrupted store file they then fix, or a transient home-directory/filesystem hiccup on the desktop sidecar) is permanently locked out of managed login and managed model selection until they restart jcode. This is an availability regression introduced by this PR.

85% confidence

Suggested change
if s.providerAuth != nil || s.providerAuthErr != nil {
return s.providerAuth, s.providerAuthErr
}
s.providerAuth, s.providerAuthErr = providerauth.Default(config.ConfigDir())
return s.providerAuth, s.providerAuthErr
}
Only cache successful initialization so failures can be retried (providerauth.Default already memoizes successful managers by config dir, so this stays cheap):
func (s *Server) providerAuthService() (ProviderAuthService, error) {
s.providerAuthMu.Lock()
defer s.providerAuthMu.Unlock()
if s.providerAuth != nil {
return s.providerAuth, nil
}
service, err := providerauth.Default(config.ConfigDir())
if err != nil {
return nil, err
}
s.providerAuth = service
return s.providerAuth, nil
}

@cnjack
cnjack marked this pull request as ready for review August 10, 2026 03:37
@cnjack
cnjack merged commit 675c353 into main Aug 10, 2026
3 of 4 checks passed
@cnjack
cnjack deleted the codex/grok-unified-auth branch August 10, 2026 03:37
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.

1 participant