How CodexBar Manages Multi-Provider Account Authentication
CodexBar stores each provider's credentials as token accounts in a single JSON file (token‑accounts.json), using FileTokenAccountStore for persistence and TokenAccountSupport for provider-specific injection methods.
The open-source macOS menu-bar application CodexBar (steipete/CodexBar) handles multi-provider account authentication by abstracting credentials into a unified token account system. This architecture allows users to switch between multiple AI providers—such as Claude, Codex, and Vertex AI—without duplicating UI code or authentication logic. By separating storage concerns from provider-specific injection methods, CodexBar maintains a single source of truth for all credentials while supporting diverse authentication flows.
Token Account Architecture
CodexBar organizes authentication around three core concerns: persistent storage, in-memory representation, and provider-specific injection strategies.
FileTokenAccountStore for JSON Persistence
In Sources/CodexBarCore/TokenAccounts.swift, the FileTokenAccountStore class conforms to the ProviderTokenAccountStoring protocol and manages the token‑accounts.json file. This store guarantees the file exists on disk and secures it with POSIX mode 0o600 (owner-read/write only) on macOS. The class provides atomic read and write operations for the entire account collection, ensuring data consistency across the application.
ProviderTokenAccount Data Structure
The ProviderTokenAccount struct defines the schema for stored credentials. Each account carries a unique UUID, a user-defined label, the raw token string, creation timestamps, and optional provider-specific fields such as organizationID and workspaceID. These instances are wrapped in ProviderTokenAccountData objects that maintain version information and track the currently active account index for each provider.
TokenAccountSupport for Provider-Specific Injection
Located in Sources/CodexBarCore/TokenAccountSupport.swift, the TokenAccountSupport protocol describes how a token should be injected into runtime environments—either as an environment variable or as a cookie header. The TokenAccountSupportCatalog provides a registry of these configurations, including the envOverride(provider:token:) method that determines the correct injection mechanism for each provider type. This abstraction allows the same UI code to handle authentication for Claude (cookie-based) and Codex (environment variable-based) without modification.
OAuth Credential Management
For providers requiring OAuth flows, CodexBar implements specialized credential stores that handle token refresh, keychain caching, and environment loading.
Keychain and File-Based Caching
The ClaudeOAuthCredentialsStore class in Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift loads OAuth tokens from three sources: environment variables, on-disk credential files (such as ~/.config/anthropic/claude.oauth), and the macOS keychain. Analogous stores exist for Codex (CodexOAuthCredentialsStore) and Vertex AI (VertexAIOAuthCredentialsStore). These stores cache tokens in memory to minimize keychain prompts and respect user-defined prompt policies during background refreshes.
Token Refresh and Validation
When a fetcher requests credentials, the OAuth store validates the token's freshness. If the token is stale, the store executes a refresh flow before returning the credential record. The store also scrubs sensitive keys from logs and handles normalization between different token formats, ensuring that the ClaudeUsageFetcher and similar components receive valid authentication headers.
The Authentication Workflow
When CodexBar queries a provider's API, the system executes a five-step pipeline:
-
Select an active token – The UI retrieves the
ProviderTokenAccountcollection fromFileTokenAccountStoreand identifies the active account using theactiveIndexproperty fromProviderTokenAccountData. -
Map token to injection – The system calls
TokenAccountSupportCatalog.envOverride(provider:token:)to determine whether the token requires an environment variable (e.g.,ANTIGRAVITY_OAUTH_TOKEN) or a cookie header (for Claude). -
Load credentials – The provider-specific fetcher requests a credential record from the appropriate
*OAuthCredentialsStore. The store returns the token from its cache, the keychain, or the on-disk file, triggering a refresh if necessary. -
Execute the request – The fetcher constructs an HTTP request using the loaded token, applying it as either an
Authorization: Bearerheader or aCookieheader based on the provider's requirements. -
Update usage UI – Results merge into the shared
UsageStore, which drives the menu-bar interface with current quota and usage statistics.
Security Implementation
CodexBar implements several layers of security to protect sensitive tokens:
- File permissions – The
token‑accounts.jsonfile is created with0o600permissions, restricting read and write access to the file owner only. - Keychain integration – OAuth tokens can be cached in the macOS keychain, with stores respecting user prompt policies to prevent unauthorized access during background operations.
- Token scrubbing – The
TokenAccountSupportdefinitions specify which keys to scrub from logs and debug output, preventing accidental token leakage.
Code Examples
Storing a New Provider Token
The following Swift code demonstrates how to persist a new Claude account using the FileTokenAccountStore:
import CodexBarCore
// 1. Load existing accounts
let store = FileTokenAccountStore()
var allAccounts = try store.loadAccounts()
// 2. Create a new token account for Claude
let newClaudeAccount = ProviderTokenAccount(
id: UUID(),
label: "My Claude Account",
token: "sk-ant-oat‑my‑token‑123",
addedAt: Date().timeIntervalSince1970,
lastUsed: nil,
externalIdentifier: nil,
usageScope: nil,
organizationID: nil,
workspaceID: nil)
// 3. Update the provider-specific data structure
var claudeData = allAccounts[.claude] ?? ProviderTokenAccountData(
version: 1,
accounts: [],
activeIndex: 0)
var accounts = claudeData.accounts
accounts.append(newClaudeAccount)
let updatedClaudeData = ProviderTokenAccountData(
version: 1,
accounts: accounts,
activeIndex: accounts.count - 1)
// 4. Persist back to disk
allAccounts[.claude] = updatedClaudeData
try store.storeAccounts(allAccounts)
This example references ProviderTokenAccount and FileTokenAccountStore from Sources/CodexBarCore/TokenAccounts.swift.
Retrieving Credentials for API Calls
To fetch usage data with a stored token, resolve the active account and apply the environment override:
import CodexBarCore
func fetchClaudeUsage() async throws -> ClaudeUsage {
// 1. Resolve the active token for Claude
let store = FileTokenAccountStore()
let accounts = try store.loadAccounts()
guard let claudeData = accounts[.claude],
let active = claudeData.accounts.first(where: {
$0.id == claudeData.accounts[claudeData.activeIndex].id
})
else { throw MyError.noClaudeAccount }
// 2. Build the environment map for injection
let env = TokenAccountSupportCatalog.envOverride(
for: .claude,
token: active.token) ?? [:]
// 3. Create fetcher with resolved environment
let fetcher = ClaudeUsageFetcher(environment: env)
return try await fetcher.fetch()
}
This pattern appears in Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift, specifically around lines 298-314, where the fetcher integrates with ClaudeOAuthCredentialsStore.
Summary
- Centralized storage – All provider credentials live in
token‑accounts.json, managed byFileTokenAccountStorewith strict file permissions. - Provider abstraction –
TokenAccountSupportandTokenAccountSupportCatalogdecouple the UI from provider-specific injection methods, supporting both environment variables and cookies. - OAuth handling – Dedicated credential stores (
ClaudeOAuthCredentialsStore,CodexOAuthCredentialsStore, etc.) handle keychain caching, token refresh, and multi-source token resolution. - Secure by default – Token files use
0o600permissions, OAuth tokens can reside in the macOS keychain, and sensitive values are scrubbed from logs.
Frequently Asked Questions
Where does CodexBar store authentication tokens?
CodexBar persists all token accounts in a JSON file named token‑accounts.json, accessed through the FileTokenAccountStore class in Sources/CodexBarCore/TokenAccounts.swift. OAuth tokens may also be cached in the macOS keychain or stored in provider-specific configuration files within ~/.config/.
How does CodexBar distinguish between different providers?
The system uses the TokenAccountSupportCatalog to maintain provider-specific metadata in Sources/CodexBarCore/TokenAccountSupportCatalog+Data.swift. Each provider (Claude, Codex, Vertex AI) has a unique TokenAccountSupport configuration that defines the environment variable key or cookie name used for token injection, allowing the same account structure to serve multiple providers.
What security measures protect stored tokens?
The token‑accounts.json file is created with POSIX mode 0o600, restricting access to the file owner. OAuth tokens can be stored in the macOS keychain, and the credential stores respect user prompt policies to prevent unauthorized background access. Additionally, the TokenAccountSupport definitions specify sensitive keys to scrub from debug output.
How does the app handle OAuth token refresh?
When a fetcher requests credentials, the corresponding *OAuthCredentialsStore (such as ClaudeOAuthCredentialsStore) checks token freshness. If the token is stale, the store executes a refresh flow before returning the credential record to the fetcher. This process occurs in Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift and analogous files for other providers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →