# How CodexBar Manages Multi-Provider Account Authentication

> Discover how CodexBar handles multi-provider account authentication by storing credentials in a single JSON file using FileTokenAccountStore and TokenAccountSupport for efficient management.

- Repository: [Peter Steinberger/CodexBar](https://github.com/steipete/CodexBar)
- Tags: how-to-guide
- Published: 2026-07-07

---

**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`](https://github.com/steipete/CodexBar/blob/main/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`](https://github.com/steipete/CodexBar/blob/main/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`](https://github.com/steipete/CodexBar/blob/main/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:

1. **Select an active token** – The UI retrieves the `ProviderTokenAccount` collection from `FileTokenAccountStore` and identifies the active account using the `activeIndex` property from `ProviderTokenAccountData`.

2. **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).

3. **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.

4. **Execute the request** – The fetcher constructs an HTTP request using the loaded token, applying it as either an `Authorization: Bearer` header or a `Cookie` header based on the provider's requirements.

5. **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.json` file is created with `0o600` permissions, 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 `TokenAccountSupport` definitions 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`:

```swift
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`](https://github.com/steipete/CodexBar/blob/main/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:

```swift
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`](https://github.com/steipete/CodexBar/blob/main/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 by `FileTokenAccountStore` with strict file permissions.
- **Provider abstraction** – `TokenAccountSupport` and `TokenAccountSupportCatalog` decouple 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 `0o600` permissions, 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`](https://github.com/steipete/CodexBar/blob/main/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`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift) and analogous files for other providers.