Skip to content

Commit 56185c2

Browse files
BREAKING: Remove licenseKey, use only OAuth2 Basic auth (v3.0.0)
- Remove licenseKey field from AxonFlowConfig - Remove X-License-Key header support - Simplify addAuthHeaders() to only use OAuth2 Basic auth - Update all tests to check for Authorization: Basic header - Update javadoc examples to use clientId/clientSecret - Update README and CHANGELOG with breaking changes Breaking Changes: - licenseKey config option removed - X-License-Key header no longer sent - clientId and clientSecret are now required for enterprise features
1 parent c2d5f11 commit 56185c2

11 files changed

Lines changed: 99 additions & 152 deletions

File tree

CHANGELOG.md

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ All notable changes to the AxonFlow Java SDK will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [2.2.0] - 2026-01-07
8+
## [3.0.0] - 2026-01-08
9+
10+
### Breaking Changes
11+
12+
- **BREAKING**: Removed `licenseKey` config option - use `clientId` and `clientSecret` instead
13+
- **BREAKING**: Removed `X-License-Key` header support - SDK now uses only OAuth2 Basic auth
14+
- **BREAKING**: `clientId` and `clientSecret` are now required for all enterprise features
915

1016
### Added
1117

@@ -17,16 +23,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1723

1824
### Changed
1925

20-
- **OAuth2 Basic Authentication**: Standardized authentication to use industry-standard OAuth2 Basic auth
26+
- **OAuth2-Only Authentication**: Simplified authentication to use only OAuth2 Basic auth
2127
- Uses `Authorization: Basic base64(clientId:clientSecret)` header
22-
- Removed non-standard `X-Client-ID` and `X-Client-Secret` headers
23-
- `X-License-Key` retained for backward compatibility (fallback when OAuth2 credentials not provided)
24-
- Matches TypeScript SDK authentication pattern for consistency across all SDKs
28+
- Removed `X-License-Key` and non-standard `X-Client-ID`/`X-Client-Secret` headers
29+
- Aligns with industry-standard OAuth2 client credentials pattern
2530

2631
### Fixed
2732

2833
- **getPlanStatus endpoint**: Fixed endpoint path from `/api/v1/orchestrator/plan/{id}` to `/api/v1/plan/{id}` to match agent proxy routes
2934

35+
### Migration Guide
36+
37+
**Before (v2.x):**
38+
```java
39+
AxonFlowConfig config = AxonFlowConfig.builder()
40+
.endpoint("http://localhost:8080")
41+
.licenseKey("AXON-V2-...")
42+
.build();
43+
```
44+
45+
**After (v3.0.0):**
46+
```java
47+
AxonFlowConfig config = AxonFlowConfig.builder()
48+
.endpoint("http://localhost:8080")
49+
.clientId("my-client-id")
50+
.clientSecret("my-client-secret")
51+
.build();
52+
```
53+
3054
## [2.1.2] - 2026-01-07
3155

3256
### Fixed

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ public class GatewayExample {
4545
// Initialize client
4646
AxonFlow client = AxonFlow.create(AxonFlowConfig.builder()
4747
.endpoint("https://agent.getaxonflow.com")
48-
.licenseKey("your-license-key")
48+
.clientId("your-client-id")
49+
.clientSecret("your-client-secret")
4950
.build());
5051

5152
// Step 1: Pre-check the request
@@ -99,7 +100,8 @@ public class ProxyExample {
99100
public static void main(String[] args) {
100101
AxonFlow client = AxonFlow.create(AxonFlowConfig.builder()
101102
.endpoint("https://agent.getaxonflow.com")
102-
.licenseKey("your-license-key")
103+
.clientId("your-client-id")
104+
.clientSecret("your-client-secret")
103105
.build());
104106

105107
ClientResponse response = client.executeQuery(
@@ -126,7 +128,8 @@ public class ProxyExample {
126128
```java
127129
AxonFlowConfig config = AxonFlowConfig.builder()
128130
.endpoint("https://agent.getaxonflow.com") // Required
129-
.licenseKey("your-license-key") // Required for cloud
131+
.clientId("your-client-id")
132+
.clientSecret("your-client-secret") // Required for cloud
130133
.timeout(Duration.ofSeconds(30)) // Default: 60s
131134
.debug(true) // Enable request logging
132135
.insecureSkipVerify(false) // SSL verification (default: false)
@@ -240,7 +243,8 @@ The SDK includes automatic retry with exponential backoff:
240243
```java
241244
AxonFlowConfig config = AxonFlowConfig.builder()
242245
.endpoint("https://agent.getaxonflow.com")
243-
.licenseKey("your-license-key")
246+
.clientId("your-client-id")
247+
.clientSecret("your-client-secret")
244248
.retryConfig(RetryConfig.builder()
245249
.maxAttempts(3)
246250
.initialDelayMs(100)
@@ -258,7 +262,8 @@ Enable caching for repeated policy checks:
258262
```java
259263
AxonFlowConfig config = AxonFlowConfig.builder()
260264
.endpoint("https://agent.getaxonflow.com")
261-
.licenseKey("your-license-key")
265+
.clientId("your-client-id")
266+
.clientSecret("your-client-secret")
262267
.cacheEnabled(true)
263268
.cacheTtl(Duration.ofMinutes(5))
264269
.cacheMaxSize(1000)
@@ -279,7 +284,8 @@ import com.getaxonflow.sdk.interceptors.*;
279284
// Initialize AxonFlow client
280285
AxonFlow axonflow = AxonFlow.create(AxonFlowConfig.builder()
281286
.endpoint("https://agent.getaxonflow.com")
282-
.licenseKey("your-license-key")
287+
.clientId("your-client-id")
288+
.clientSecret("your-client-secret")
283289
.build());
284290

285291
// Create interceptor

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.getaxonflow</groupId>
88
<artifactId>axonflow-sdk</artifactId>
9-
<version>2.2.0</version>
9+
<version>3.0.0</version>
1010
<packaging>jar</packaging>
1111

1212
<name>AxonFlow Java SDK</name>

src/main/java/com/getaxonflow/sdk/AxonFlow.java

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -888,11 +888,7 @@ public ConnectorResponse queryConnector(ConnectorQuery query) {
888888
context.put("params", query.getParameters());
889889
}
890890

891-
// Determine clientId: prefer config.getClientId(), fallback to license key
892891
String clientId = config.getClientId();
893-
if (clientId == null || clientId.isEmpty()) {
894-
clientId = config.getLicenseKey();
895-
}
896892

897893
ClientRequest clientRequest = ClientRequest.builder()
898894
.query(query.getOperation())
@@ -1668,20 +1664,11 @@ private void addAuthHeaders(Request.Builder builder) {
16681664
}
16691665

16701666
// OAuth2-style: Authorization: Basic base64(clientId:clientSecret)
1671-
if (config.getClientId() != null && !config.getClientId().isEmpty() &&
1672-
config.getClientSecret() != null && !config.getClientSecret().isEmpty()) {
1673-
String credentials = config.getClientId() + ":" + config.getClientSecret();
1674-
String encoded = Base64.getEncoder().encodeToString(
1675-
credentials.getBytes(StandardCharsets.UTF_8)
1676-
);
1677-
builder.header("Authorization", "Basic " + encoded);
1678-
return;
1679-
}
1680-
1681-
// Fallback: X-License-Key header (backward compatibility)
1682-
if (config.getLicenseKey() != null && !config.getLicenseKey().isEmpty()) {
1683-
builder.header("X-License-Key", config.getLicenseKey());
1684-
}
1667+
String credentials = config.getClientId() + ":" + config.getClientSecret();
1668+
String encoded = Base64.getEncoder().encodeToString(
1669+
credentials.getBytes(StandardCharsets.UTF_8)
1670+
);
1671+
builder.header("Authorization", "Basic " + encoded);
16851672
}
16861673

16871674
/**
@@ -1693,7 +1680,7 @@ private void addAuthHeaders(Request.Builder builder) {
16931680
private void requireCredentials(String feature) {
16941681
if (!config.hasCredentials()) {
16951682
throw new AuthenticationException(
1696-
feature + " requires credentials. Set licenseKey or clientId/clientSecret in config."
1683+
feature + " requires credentials. Set clientId and clientSecret in config."
16971684
);
16981685
}
16991686
}

src/main/java/com/getaxonflow/sdk/AxonFlowConfig.java

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ public final class AxonFlowConfig {
5151
private final String endpoint;
5252
private final String clientId;
5353
private final String clientSecret;
54-
private final String licenseKey;
5554
private final Mode mode;
5655
private final Duration timeout;
5756
private final boolean debug;
@@ -64,7 +63,6 @@ private AxonFlowConfig(Builder builder) {
6463
this.endpoint = normalizeUrl(builder.endpoint != null ? builder.endpoint : DEFAULT_ENDPOINT);
6564
this.clientId = builder.clientId;
6665
this.clientSecret = builder.clientSecret;
67-
this.licenseKey = builder.licenseKey;
6866
this.mode = builder.mode != null ? builder.mode : Mode.PRODUCTION;
6967
this.timeout = builder.timeout != null ? builder.timeout : DEFAULT_TIMEOUT;
7068
this.debug = builder.debug;
@@ -87,13 +85,13 @@ private void validate() {
8785
/**
8886
* Checks if credentials are configured.
8987
*
90-
* <p>Returns true if either a license key or client credentials are set.
88+
* <p>Returns true if client credentials (clientId and clientSecret) are set.
9189
*
9290
* @return true if credentials are available
9391
*/
9492
public boolean hasCredentials() {
95-
return (licenseKey != null && !licenseKey.isEmpty()) ||
96-
(clientId != null && clientSecret != null && !clientSecret.isEmpty());
93+
return clientId != null && !clientId.isEmpty() &&
94+
clientSecret != null && !clientSecret.isEmpty();
9795
}
9896

9997
private String normalizeUrl(String url) {
@@ -122,7 +120,6 @@ public boolean isLocalhost() {
122120
* <li>AXONFLOW_AGENT_URL - The endpoint URL (kept for backwards compatibility)</li>
123121
* <li>AXONFLOW_CLIENT_ID - The client ID</li>
124122
* <li>AXONFLOW_CLIENT_SECRET - The client secret</li>
125-
* <li>AXONFLOW_LICENSE_KEY - The license key</li>
126123
* <li>AXONFLOW_MODE - Operating mode (production/sandbox)</li>
127124
* <li>AXONFLOW_TIMEOUT_SECONDS - Request timeout in seconds</li>
128125
* <li>AXONFLOW_DEBUG - Enable debug mode (true/false)</li>
@@ -149,11 +146,6 @@ public static AxonFlowConfig fromEnvironment() {
149146
builder.clientSecret(clientSecret);
150147
}
151148

152-
String licenseKey = System.getenv("AXONFLOW_LICENSE_KEY");
153-
if (licenseKey != null && !licenseKey.isEmpty()) {
154-
builder.licenseKey(licenseKey);
155-
}
156-
157149
String modeStr = System.getenv("AXONFLOW_MODE");
158150
if (modeStr != null && !modeStr.isEmpty()) {
159151
builder.mode(Mode.fromValue(modeStr));
@@ -188,10 +180,6 @@ public String getClientSecret() {
188180
return clientSecret;
189181
}
190182

191-
public String getLicenseKey() {
192-
return licenseKey;
193-
}
194-
195183
public Mode getMode() {
196184
return mode;
197185
}
@@ -233,13 +221,12 @@ public boolean equals(Object o) {
233221
insecureSkipVerify == that.insecureSkipVerify &&
234222
Objects.equals(endpoint, that.endpoint) &&
235223
Objects.equals(clientId, that.clientId) &&
236-
Objects.equals(licenseKey, that.licenseKey) &&
237224
mode == that.mode;
238225
}
239226

240227
@Override
241228
public int hashCode() {
242-
return Objects.hash(endpoint, clientId, licenseKey, mode, debug, insecureSkipVerify);
229+
return Objects.hash(endpoint, clientId, mode, debug, insecureSkipVerify);
243230
}
244231

245232
@Override
@@ -260,7 +247,6 @@ public static final class Builder {
260247
private String endpoint;
261248
private String clientId;
262249
private String clientSecret;
263-
private String licenseKey;
264250
private Mode mode;
265251
private Duration timeout;
266252
private boolean debug;
@@ -321,17 +307,6 @@ public Builder clientSecret(String clientSecret) {
321307
return this;
322308
}
323309

324-
/**
325-
* Sets the license key for SaaS authentication.
326-
*
327-
* @param licenseKey the license key
328-
* @return this builder
329-
*/
330-
public Builder licenseKey(String licenseKey) {
331-
this.licenseKey = licenseKey;
332-
return this;
333-
}
334-
335310
/**
336311
* Sets the operating mode.
337312
*

src/main/java/com/getaxonflow/sdk/interceptors/AnthropicInterceptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
* // Create AxonFlow client
3030
* AxonFlow axonflow = AxonFlow.builder()
3131
* .agentUrl("http://localhost:8080")
32-
* .licenseKey("your-license-key")
32+
* .clientId("your-client-id").clientSecret("your-client-secret")
3333
* .build();
3434
*
3535
* // Create interceptor

src/main/java/com/getaxonflow/sdk/interceptors/OpenAIInterceptor.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@
3030
* <pre>{@code
3131
* // Create AxonFlow client
3232
* AxonFlow axonflow = AxonFlow.builder()
33-
* .agentUrl("http://localhost:8080")
34-
* .licenseKey("your-license-key")
33+
* .endpoint("http://localhost:8080")
34+
* .clientId("your-client-id")
35+
* .clientSecret("your-client-secret")
3536
* .build();
3637
*
3738
* // Create interceptor

src/main/java/com/getaxonflow/sdk/interceptors/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* // Create AxonFlow client
2424
* AxonFlow axonflow = AxonFlow.builder()
2525
* .agentUrl("http://localhost:8080")
26-
* .licenseKey("your-license-key")
26+
* .clientId("your-client-id").clientSecret("your-client-secret")
2727
* .build();
2828
*
2929
* // Wrap OpenAI calls

src/test/java/com/getaxonflow/sdk/AxonFlowConfigTest.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ void shouldCreateFullConfig() {
6161
.endpoint("https://api.example.com")
6262
.clientId("test-client")
6363
.clientSecret("test-secret")
64-
.licenseKey("test-license")
6564
.mode(Mode.SANDBOX)
6665
.timeout(Duration.ofSeconds(30))
6766
.debug(true)
@@ -74,7 +73,6 @@ void shouldCreateFullConfig() {
7473
assertThat(config.getEndpoint()).isEqualTo("https://api.example.com");
7574
assertThat(config.getClientId()).isEqualTo("test-client");
7675
assertThat(config.getClientSecret()).isEqualTo("test-secret");
77-
assertThat(config.getLicenseKey()).isEqualTo("test-license");
7876
assertThat(config.getMode()).isEqualTo(Mode.SANDBOX);
7977
assertThat(config.getTimeout()).isEqualTo(Duration.ofSeconds(30));
8078
assertThat(config.isDebug()).isTrue();
@@ -111,7 +109,7 @@ void shouldDetectLocalhost(String url) {
111109
void shouldDetectNonLocalhost(String url) {
112110
AxonFlowConfig config = AxonFlowConfig.builder()
113111
.endpoint(url)
114-
.licenseKey("test-key")
112+
.clientId("test-client").clientSecret("test-secret")
115113
.build();
116114

117115
assertThat(config.isLocalhost()).isFalse();
@@ -129,17 +127,6 @@ void shouldAllowNonLocalhostWithoutCredentials() {
129127
assertThat(config.getEndpoint()).isEqualTo("https://api.example.com");
130128
}
131129

132-
@Test
133-
@DisplayName("should accept license key for non-localhost")
134-
void shouldAcceptLicenseKeyForNonLocalhost() {
135-
AxonFlowConfig config = AxonFlowConfig.builder()
136-
.endpoint("https://api.example.com")
137-
.licenseKey("test-license")
138-
.build();
139-
140-
assertThat(config.getLicenseKey()).isEqualTo("test-license");
141-
}
142-
143130
@Test
144131
@DisplayName("should accept client credentials for non-localhost")
145132
void shouldAcceptClientCredentialsForNonLocalhost() {

0 commit comments

Comments
 (0)