The credential balancer manages pools of upstream credentials (API keys, OAuth tokens, etc.) for a given provider and rotates between them based on health. It integrates as a system plugin and exposes a registry key (auth manager) that provider plugins can use to fetch a currently healthy credential at request time.
- Balances across multiple credential files per provider.
- Detects failures from HTTP responses and temporarily disables bad credentials with cooldowns.
- Supports manual refresh, proportional selection, sticky-on-success, and backoff.
- Exposes a named auth manager registry key (defaults to
<provider>_credential_balancer).
Use the balancer when you have multiple tokens for the same provider and want resilient failover and automatic rotation without changing application code or secrets storage.
The following minimal example configures CCproxy with the Codex provider to use a pool of Codex OAuth tokens.
[plugins]
# Enable the credential balancer system plugin
enabled_plugins = [
"codex",
"oauth_codex",
"credential_balancer"
]
# Point the codex provider at the balancer-managed auth manager
[plugins.codex]
auth_manager = "codex_credential_balancer"
[[plugins.credential_balancer.providers]]
provider = "codex"
strategy = "round_robin" # or "failover"
manager_class = "ccproxy.plugins.oauth_codex.manager.CodexTokenManager"
storage_class = "ccproxy.plugins.oauth_codex.storage.CodexTokenStorage"
credentials = [
{ path = "~/.config/ccproxy/codex_plus.json" },
{ path = "~/.config/ccproxy/codex_pro.json" },
]
Enable the system plugin and define one or more provider pools. Each pool declares where to read credentials from and optional tuning parameters. See config.example.toml for full, commented examples.
[[plugins.credential_balancer.providers]]
# Provider identifier, e.g. "claude-api", "openai", "codex".
provider = "claude-api"
strategy = "round_robin" # or "failover"
max_failures_before_disable = 2
cooldown_seconds = 120.0
failure_status_codes = [401, 403]
# Pool defaults (example: Claude OAuth manager/storage)
manager_class = "ccproxy.plugins.oauth_claude.manager.ClaudeApiTokenManager"
storage_class = "ccproxy.plugins.oauth_claude.storage.ClaudeOAuthStorage"
credentials = [
{ type = "manager", file = "~/.config/ccproxy/claude_primary.json", label = "primary" },
{ type = "manager", file = "~/.config/ccproxy/claude_backup.json", label = "backup" },
]After defining a pool, point the corresponding provider plugin at the balancer by overriding its auth manager to the registry key:
[plugins.claude-api]
# Use the balancer-provided registry entry instead of a static key file
auth_manager = "claude-api_credential_balancer"If you set a custom manager_name in the balancer configuration, use that value for auth_manager instead.
- Startup: for each entry in
[[plugins.credential_balancer.providers]], the plugin constructs a Manager that loads credentials from the declared files and registers it undermanager_name. - Request path: provider adapters ask the registry for a credential via the
auth_managerkey; the balancer selects a currently healthy token. - Feedback loop: the
credential_balancerhook observes provider HTTP responses and records failures/successes to update health, handle cooldowns, and trigger failover when necessary.
- Extract cooldown period from provider error responses and apply dynamic per-credential cooldowns.
- Collect and parse HTTP error payloads/headers in the hook (e.g., Retry-After or equivalent fields).
- Pass an optional cooldown override with the failure event to the manager.
- Ensure logs include the derived cooldown value for observability.
The plugin emits structured events to aid troubleshooting, including (non-exhaustive):
credential_balancer_manager_registeredcredential_balancer_token_selectedcredential_balancer_failure_detectedcredential_balancer_failovercredential_balancer_manual_refresh_succeeded
During development, server logs stream to /tmp/ccproxy/ccproxy.log when running ccproxy serve.
- Runtime code:
ccproxy/plugins/credential_balancer/plugin.py: plugin factory and lifecycle wiringmanager.py: rotation, health, selection, and feedback processinghook.py: HTTP lifecycle hook that feeds response outcomes back to the managerconfig.py: Pydantic models for pool configuration and defaults
- Enable via
pyproject.tomlentry pointcredential_balancer(already wired).
- Unit tests:
tests/plugins/credential_balancer/unit/ - Run fast tests:
./Taskfile test-unit - Full suite:
./Taskfile test
Follow the project’s testing markers and async patterns as described in TESTING.md.
- Authentication overview:
docs/user-guide/authentication.md - Example configuration:
config.example.toml
Commands
uv run ccproxy serve(logs at/tmp/ccproxy/ccproxy.log)