Skip to content

feat: add client caching to reduce OAuth token requests#63

Open
spbsoluble wants to merge 2 commits intomainfrom
fix/oauth-client-caching
Open

feat: add client caching to reduce OAuth token requests#63
spbsoluble wants to merge 2 commits intomainfrom
fix/oauth-client-caching

Conversation

@spbsoluble
Copy link
Contributor

Summary

  • Introduces a ClientCache that caches Command API clients by configuration hash
  • Reuses cached clients across reconciliations, allowing the underlying golang.org/x/oauth2 token caching to work as intended
  • Reduces OAuth token endpoint calls from once-per-request to once-per-token-expiry

Problem

When using OAuth authentication, every certificate request reconciliation created a new Command API client. This meant:

  1. A new clientcredentials.Config.TokenSource() was created each time
  2. The token cache in the oauth2 library was thrown away with each new client
  3. Every request triggered a new token fetch from the OAuth provider

For customers with OAuth provider quotas (common with enterprise IdPs), this caused rate limiting and quota exhaustion issues.

Solution

The fix introduces a ClientCache in internal/command/client_cache.go that:

  • Caches clients by configuration hash: Uses SHA-256 hash of all config fields (hostname, credentials, scopes, etc.) as the cache key
  • Thread-safe: Uses sync.RWMutex for safe concurrent access during reconciliations
  • Shared across controllers: Both IssuerReconciler and CertificateRequestReconciler use the same cache instance
  • Minimal code changes: Only cmd/main.go needed modification to create and inject the cache

Cache Key Design

The cache key includes all fields that affect the client connection:

  • Hostname and API path
  • CA certificates
  • Basic auth credentials (if used)
  • OAuth credentials, scopes, and audience (if used)
  • Ambient credential configuration

This ensures:

  • Different issuers get different clients
  • Same issuer reuses its client across requests
  • Credential rotation (via secret update) automatically gets a new client (different hash)

Test plan

  • Added unit tests for configHash() function
  • Added unit tests for ClientCache basic operations
  • Verified build compiles successfully
  • All existing tests continue to pass

Manual testing

To verify the fix works:

  1. Deploy the updated controller
  2. Monitor OAuth provider logs/metrics
  3. Issue multiple certificates using the same issuer
  4. Confirm only one token request is made (until token expires)

🤖 Generated with Claude Code

spbsoluble and others added 2 commits February 25, 2026 10:25
Previously, every certificate request reconciliation created a new Command
API client, which meant a new OAuth token was fetched for each request.
For customers with OAuth provider quotas, this caused rate limiting issues.

This change introduces a ClientCache that:
- Caches Command API clients by configuration hash
- Reuses cached clients across reconciliations for the same issuer
- Allows the underlying oauth2 library's token caching to work as intended
- Is thread-safe for concurrent reconciliations

The cache key is a SHA-256 hash of all configuration fields that affect
the client connection (hostname, API path, credentials, scopes, etc.),
ensuring different issuers get different clients while the same issuer
reuses its client.

Fixes: OAuth token re-authentication on every request

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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