feat(anthropic): support bearer token authentication - #3038
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
🟢 Approval recommended
The implementation cleanly forwards authToken to the underlying SDK, preserves backward compatibility and configuration precedence, and is covered by focused local HTTP regression tests.
Pull request overview
This PR adds first-class Bearer token authentication support for the Anthropic model integration, enabling Anthropic-compatible gateways that require Authorization: Bearer <token> while preserving existing API key behavior and configuration precedence in the Spring Boot starter.
Changes:
- Extend
AnthropicChatModel.Builderand constructors to accept anauthTokenand forward it to the underlying Anthropic SDK client. - Add Spring Boot property binding for
agentscope.anthropic.auth-tokenand wire it into auto-configuration (with blank-value handling and customizer override preserved). - Add regression tests (local MockWebServer) and update both EN/ZH docs with builder and Spring Boot configuration examples.
File summaries
| File | Description |
|---|---|
| docs/v2/zh/integration/model/anthropic.md | Adds ZH usage notes and examples for Bearer token authentication via builder and Spring Boot properties. |
| docs/v2/en/integration/model/anthropic.md | Adds EN usage notes and examples for Bearer token authentication via builder and Spring Boot properties. |
| agentscope-extensions/agentscope-spring-boot-starters/agentscope-anthropic-spring-boot-starter/src/test/java/io/agentscope/spring/boot/anthropic/AnthropicAutoConfigurationTest.java | Adds Spring Boot regression tests verifying auth-token binding, blank handling, and customizer precedence via real HTTP calls to MockWebServer. |
| agentscope-extensions/agentscope-spring-boot-starters/agentscope-anthropic-spring-boot-starter/src/main/java/io/agentscope/spring/boot/anthropic/AnthropicProperties.java | Introduces authToken configuration property with accessor methods and Javadoc. |
| agentscope-extensions/agentscope-spring-boot-starters/agentscope-anthropic-spring-boot-starter/src/main/java/io/agentscope/spring/boot/anthropic/AnthropicAutoConfiguration.java | Wires auth-token into AnthropicChatModel.Builder and keeps existing trimming/customizer order. |
| agentscope-extensions/agentscope-extensions-model/agentscope-extensions-model-anthropic/src/test/java/io/agentscope/extensions/model/anthropic/AnthropicChatModelAuthenticationTest.java | Adds integration-style tests ensuring configured headers are sent in streaming/non-streaming modes and constructor backward compatibility. |
| agentscope-extensions/agentscope-extensions-model/agentscope-extensions-model-anthropic/src/main/java/io/agentscope/extensions/model/anthropic/AnthropicChatModel.java | Adds authToken support to builder and a new constructor overload that forwards to the SDK client builder. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
@qiyu-lu This PR currently conflicts with git fetch origin
git checkout feat/anthropic-bearer-auth
git rebase origin/main
# resolve conflicts, then:
git push --force-with-leaseThis is a one-time reminder. Feel free to @mention me for a re-review once conflicts are resolved. Automated notification by github-manager-bot |
oss-maintainer
left a comment
There was a problem hiding this comment.
Summary
Adds bearer-token auth for Anthropic-compatible gateways on top of the existing API-key path, threaded through the builder and the Spring auto-configuration, with MockWebServer assertions on the actual Authorization header. That is the right way to test this. Two things before this can move: the PR is in conflict with main, and the both-credentials-configured case currently sends two conflicting auth headers silently.
Automated review by github-manager-bot
Additional notes (not anchored to a changed line)
- [INFO]
agentscope-extensions/agentscope-extensions-model/agentscope-extensions-model-anthropic/src/main/java/io/agentscope/extensions/model/anthropic/AnthropicChatModel.java:1— Two follow-ups: (1) this PR currently conflicts withmain— see the reminder comment, please rebase; (2) please confirm the bearer token never reachestoString()/equals()/logging on the model or its config object, per the project rule that credentials must not leak into logs or events. The MockWebServer assertion in the new test is good evidence for the header itself; atoString()redaction check would close the loop. (line outside diff)
|
|
||
| /** | ||
| * Sets the bearer token for authentication with an Anthropic-compatible gateway. | ||
| * |
There was a problem hiding this comment.
The javadoc says that if both apiKey and authToken are set the SDK sends both headers, and the builder just forwards them. Silently sending two conflicting credentials is the kind of thing that produces a confusing 401 from the gateway; for an Anthropic-compatible proxy with a static Authorization header this is also a footgun in the Spring starter wiring. Consider rejecting the combination in build() (or ignoring apiKey when authToken is present and logging a warning) so the effective credential is unambiguous.
90f8699 to
0f7a4f6
Compare
oss-maintainer
left a comment
There was a problem hiding this comment.
Summary
Re-reviewed after conflict resolution and the follow-up commits. The dual-credential concern from my earlier review is now fixed at the API level (apiKey/authToken are mutually exclusive and the message never echoes the secret values), the Spring starter trims blanks before validation, and the new MockWebServer tests assert the actual X-Api-Key / Authorization headers on both the streaming and non-streaming paths. CI is green and the CLA is signed — LGTM, with two non-blocking points below about places where the new guarantee is not yet enforced (blank strings via the public builder, and the SPI/registry path that still cannot express a bearer token).
Automated review by github-manager-bot
| AnthropicBaseFormatter formatter, | ||
| ProxyConfig proxyConfig, | ||
| String cacheTtl) { | ||
| if (apiKey != null && authToken != null) { |
There was a problem hiding this comment.
The guard is null-based, but Builder.apiKey("") / authToken(" ") are stored verbatim, so a blank credential slips through: apiKey="" + authToken="x" reaches the SDK with both headers, and authToken="" sends a malformed Authorization: Bearer . The starter trims blanks (trimToNull) before calling the builder, but this class is public API, so the same policy should be enforced here too — please normalize blank → null in the setters/constructor and only reject when two present credentials conflict, so the documented guarantee holds for direct builder users as well.
| clientBuilder.apiKey(apiKey); | ||
| } | ||
|
|
||
| if (authToken != null) { |
There was a problem hiding this comment.
Feature-scope gap: the SPI / model-registry path (AnthropicModelProvider.create() → firstNonBlank(context.getApiKey(), ANTHROPIC_API_KEY)) still has no way to pass a bearer token — ModelCreationContext exposes only apiKey/baseUrl/options, and AnthropicCredential requires a non-null apiKey. So gateway users who configure models through the registry (non-Spring) get no authToken, while the docs page added here presents bearer auth as a general model capability. Could you either extend provider + credential + context with auth_token, or state in the doc that bearer auth currently covers the builder and Spring starter paths only?
| * @param authToken the token without the {@code Bearer } prefix (null to omit) | ||
| * @return this builder | ||
| */ | ||
| public Builder authToken(String authToken) { |
There was a problem hiding this comment.
shouldNotExposeBearerTokenInModelOrBuilderToString passes only because neither Builder nor AnthropicChatModel overrides toString() today. That makes the guarantee accidental — a future @ToString/record refactor on the builder would silently start printing authToken (and apiKey) into logs. Since this PR is exactly about credential hygiene, it would be nice to add an explicit redacting toString() here (e.g. print authToken=***) so the test pins real behaviour.
| * <p>{@code apiKey} and {@code authToken} are mutually exclusive. | ||
| * | ||
| * @param baseUrl the base URL for the Anthropic API (null for default) | ||
| * @param apiKey the API key for authentication (null to omit) |
There was a problem hiding this comment.
Minor javadoc drift: the pre-existing constructor documents apiKey as "null to load from ANTHROPIC_API_KEY env var", while this one says "null to omit", and the new @throws line doesn't mention that the two-credential check is what changed. Aligning the wording (and noting explicitly that env-var fallback happens in AnthropicModelProvider, not in this constructor) would keep the two overloads from reading as different contracts.
AgentScope-Java Version
2.0.3-SNAPSHOT
Description
Fixes #3029.
Anthropic 兼容网关需要
Authorization: Bearer <token>时,现有模型无法通过 Builder 配置该凭据。本 PR 增加 SDK 客户端级别的 Bearer Token 支持,并保留原有 API Key 用法和公开构造方法。AnthropicChatModel.Builder.authToken和 Spring Boot 配置agentscope.anthropic.auth-token,由底层 SDK 设置认证头。IllegalArgumentException,异常只包含配置项名称,不包含凭据值。校验覆盖 Builder 和直接构造入口。apiKey(null)或authToken(null)清除其中一种凭据。toString()/ 校验异常中的回归测试。Validation
c5db8f72完成本地变基,并解决两处文档链接冲突。mvn -B -pl agentscope-extensions/agentscope-extensions-model/agentscope-extensions-model-anthropic,agentscope-extensions/agentscope-spring-boot-starters/agentscope-anthropic-spring-boot-starter -am '-Dtest=Anthropic*Test' -Dsurefire.failIfNoSpecifiedTests=false spotless:apply test:198 个用例,0 failures、0 errors、1 skipped。mvn -o -B ... -am spotless:check:通过。git diff --check:通过。HTTP 测试使用真实 Anthropic SDK 请求本地 MockWebServer,覆盖流式/非流式调用、Token 单独配置、API Key 单独配置、旧构造方法,以及 Starter 的空白值和 customizer 覆盖行为。新增测试覆盖双凭据拒绝、customizer 消除冲突,以及模型、Builder、配置对象和校验异常的凭据保护。未执行真实企业网关/付费模型联调或全仓测试;这些检查不代表所有 SDK 异常和日志路径均已验证。