feat(auth): auth(apikey) helper with refresh-on-401 + TokenStore#1
Merged
Conversation
… TokenStore
One-call setup for SDK adopters: `QTSurfer.auth(apikey)` exchanges a
long-lived API key for a short-lived JWT and returns an
`AuthenticatedClient` mirroring the existing `QTSurfer` workflow
surface (compile / backtest / exchanges / instruments / tickers /
klines), with transparent refresh-on-401 (refresh once, retry once,
surface the error otherwise).
* Reads `QTSURFER_APIKEY` from the environment when no argument is
passed; an explicit argument always wins.
* Pluggable `TokenStore` interface (`load` / `save` / `clear`) with
an in-memory default (`InMemoryTokenStore`). Adopters can plug in a
file, a secret manager, or a desktop keychain.
* `AuthOptions` configures base URL, token store, HTTP client, and
executor. Defaults to `https://api.qtsurfer.com/v1` + in-memory store.
* New `QTSAuthError` for missing-apikey and JWT-exchange failures.
Bumps `com.qtsurfer:api-client-java` to 0.3.1 (adds AuthApi,
AuthTokenResponse, AuthTokenError). Bumps sdk version to 0.5.0.
`DownloadFormat#wire()` is now `public` so the auth-session can pass
the underlying `ExchangeBinaryDownloads.Format` through without
re-encoding.
Tests: 11 new unit tests for the auth surface (explicit-apikey,
env-var resolution via the package-private overload, blank-apikey,
mint-401, store-save, store-seed, refresh-happy, refresh-fail,
non-401-passthrough, clear) plus 3 offline integration tests against
a local HttpServer (no live network).
Pre-existing Mockito-based tests (`BacktestWorkflowTest`,
`DomainObjectsTest`) fail on JDK 25 because Mockito's inline mock
maker can't modify generated `final` classes — unrelated to this PR;
reproducible on `origin/main`.
JitPack with the registered com.qtsurfer domain uses the GitHub repo name as the artifactId, not pom <artifactId>. Renaming sdk → sdk-java in the pom makes the published name (com.qtsurfer:sdk-java) match the local mvn install name match the README snippets. Companion change in api-client-java is in PR #2 on that repo (com.qtsurfer:api-client-java).
Matches the api-client-java approach: the badge above the snippet is the source of truth for the latest published version on JitPack; stamping a literal 0.5.0 forced a sync we kept losing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 3 of openapi-auth-rollout. Adds the
QTSurfer.auth(apikey)helper that wraps the api-client with automatic JWT refresh, env-var pickup, and a pluggable TokenStore.QTSurfer.auth(String apikey)/QTSurfer.auth()/QTSurfer.auth(String, AuthOptions)→AuthenticatedClient.QTSURFER_APIKEYenv.AuthenticatedClientmirrors theQTSurfersurface (compile,backtest,exchanges,instruments,tickers,klines) and addsrefresh(),ensureToken(),clear(),token().interface TokenStore { AuthTokenResponse load(); void save(AuthTokenResponse); void clear(); }withInMemoryTokenStoredefault (AtomicReference-backed).Notes for review
api.qtsurfer.com(prod target).auth(apikey)quickstart per goal spec.0.4.1→0.5.0.com.qtsurfer:api-client0.3.1 from Phase 2.Test plan
AuthenticatedClientTest) passAuthHelperIntegrationTest) passBacktestWorkflowTest/DomainObjectsTest(not from this PR — Mockito inline mock maker vs newer JDK finals; reproduces onmain)