Skip to content

Add multi-token support for HxClient#52

Merged
pditommaso merged 11 commits intomasterfrom
pd/multi-token-support
Feb 22, 2026
Merged

Add multi-token support for HxClient#52
pditommaso merged 11 commits intomasterfrom
pd/multi-token-support

Conversation

@pditommaso
Copy link
Contributor

@pditommaso pditommaso commented Feb 20, 2026

Summary

Extends lib-httpx to support multi-tenant JWT authentication. A single HxClient instance can now manage multiple concurrent auth sessions, each with independent token refresh.

What's new

  • HxAuth interface — Represents an auth session with a stable id() across token refreshes. Each session can carry its own refresh URL, falling back to global config
  • HxTokenStore interface — Pluggable token storage (default: in-memory ConcurrentHashMap). Implement for distributed deployments (Redis, database, etc.)
  • Per-request auth overloadssend(request, auth, handler) and sendAsync(request, auth, handler) route each request through its own auth context with automatic 401 refresh
  • Thread-safe refresh coordination — Concurrent refreshes for the same session are deduplicated; per-refresh HttpClient prevents cross-tenant cookie leakage

Design notes

  • DefaultHxAuth is suitable for simple scenarios. Production multi-tenant deployments should implement HxAuth with explicit identifiers (e.g., tenant ID) for collision-free token store keys
  • Fully backward compatible — existing single-token usage unchanged

Known limitations

  • Refresh HttpClient hardcodes HTTP/1.1 and redirect policy instead of inheriting from main client config
  • A new HttpClient is created per refresh to isolate cookies; may cause resource pressure under high concurrency

Test plan

  • HxAuth contract: stable identity, token masking, null handling
  • HxTokenStore: CRUD and putIfAbsent semantics
  • HxTokenManager: multi-session lifecycle, per-auth refresh URL, stateless resolution
  • Backward compatibility: existing HxClient tests pass unchanged

pditommaso and others added 11 commits January 5, 2026 18:42
Introduce HxAuth, HxTokenStore, and HxMapTokenStore to support
multiple authentication sessions with automatic token refresh.

- HxAuth: Immutable JWT credential container with SHA-256 key
- HxTokenStore: Interface for pluggable token storage
- HxMapTokenStore: Default ConcurrentHashMap implementation
- HxTokenManager: Extended with multi-token methods
- HxClient.Builder: Added tokenStore() method for custom stores

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Move key() method from HxTokenStore to HxAuth as static method
- Add keyOrDefault(auth, defaultValue) for null-safe key computation
- Remove key() default method from HxTokenStore interface
- key() now throws IllegalArgumentException for null auth

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Refactored no-arg methods to delegate to their HxAuth counterparts:
- addAuthHeader() - delegates with basic auth fallback
- canRefreshToken() - delegates to canRefreshToken(HxAuth)
- refreshToken() - delegates to refreshToken(HxAuth)
- doRefreshToken() - delegates to doRefreshToken(HxAuth)
- refreshTokenAsync() - delegates to refreshTokenAsync(HxAuth)
- getOrRefreshTokenAsync() - delegates to getOrRefreshTokenAsync(HxAuth)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
… multi-token support

- Add synchronized to updateTokens to prevent read-modify-write race
- Add putIfAbsent to HxTokenStore interface for atomic check-and-set in getAuth
- Create per-refresh CookieManager/HttpClient to prevent cross-user cookie leaking
- Mask tokens in HxAuth.toString() to prevent credential leaking in logs
- Reject null access token in HxAuth constructor
- Update stale Javadoc referencing removed ReentrantReadWriteLock
- Fix README putIfAbsent example to match actual interface signature
- Reduce updateTokens visibility to package-private

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add private applyAuthHeader, canRefreshToken, and refreshToken helpers
that accept nullable HxAuth and delegate to the appropriate tokenManager
method, simplifying sendWithRetry and sendWithRetryAsync.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Extract HxAuth from final class to interface with stable id() contract
- Add DefaultHxAuth as immutable record with UUID-based identity
  preserved across withToken/withRefresh
- Add per-auth refreshUrl with fallback to global config
- Remove static factory methods and keyOrDefault helper
- Replace SHA-256 key derivation with stable UUID identity
- Update README with new interface design and usage examples

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Fix stable stable typo in HxAuth Javadoc
- Update HxTokenStore Javadoc to reference HxAuth.id() instead of SHA-256
- Use two-arg remove(key, future) in refresh coordination to prevent
  accidental removal of a concurrent callers future
- Make canRefreshToken(HxAuth) side-effect-free by using tokenStore.get()
  instead of getAuth() which calls putIfAbsent
- Add comment clarifying updateTokens synchronized scope
- Update HxTokenManager class Javadoc with current API example
- Remove DefaultHxAuth references from README (package-private)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…auth test

- Remove 8 unused methods from HxTokenManager (refreshToken, refreshTokenAsync,
  doRefreshToken, getBasicAuthToken, getTokenStore, updateTokens and their overloads)
- Replace UUID-based HxAuth id with deterministic id derived from accessToken
  and refreshUrl using Objects.hash, so stateless requests always resolve to
  the same token store entry
- Simplify HxClient.refreshToken to use getDefaultAuth fallback
- Add test verifying stateless requests resolve refreshed tokens by same id

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…terface, update docs

- Rename withToken → withAccessToken, withRefresh → withRefreshToken for clarity
- Remove createdAt/updatedAt from HxAuth interface (kept in DefaultHxAuth only)
- Add Future Improvements section in README for refresh HttpClient reuse
- Add README note about DefaultHxAuth 32-bit hash limitation and stronger alternatives
- Fix DEFAULT_KEY → DEFAULT_TOKEN comment typo in HxTokenManager

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@pditommaso pditommaso merged commit 9e99b4a into master Feb 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant