Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ java {

group = 'com.phenoml.maven'

version = '8.3.0'
version = '9.0.0'

jar {
dependsOn(":generatePomFileForMavenPublication")
Expand Down Expand Up @@ -78,7 +78,7 @@ publishing {
maven(MavenPublication) {
groupId = 'com.phenoml.maven'
artifactId = 'phenoml-java-sdk'
version = '8.3.0'
version = '9.0.0'
from components.java
pom {
name = 'phenoml'
Expand Down
49 changes: 49 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,52 @@
## 9.0.0 - 2026-03-04

### Breaking Changes

- **Authentication**: Replaced username/password authentication with OAuth 2.0 client credentials. Builders now accept `clientId()` and `clientSecret()` (defaulting to `PHENOML_CLIENT_ID` and `PHENOML_CLIENT_SECRET` environment variables). Tokens are automatically obtained and refreshed via the `/v2/auth/token` endpoint.
- **Client renamed**: `PhenoML` → `PhenomlClient`, `AsyncPhenoML` → `AsyncPhenomlClient`.
- **Builder renamed**: `PhenoMLBuilder` → `PhenomlClientBuilder`, `AsyncPhenoMLBuilder` → `AsyncPhenomlClientBuilder`.
- **Wrapper clients removed**: `Client.java` and `AsyncClient.java` convenience wrappers have been removed. Use `PhenomlClient` / `AsyncPhenomlClient` directly.

### Migration Guide

**Authentication** — replace username/password with client credentials:

```java
// Before
PhenoMLClient client = PhenoMLClient.withCredentials(
"user", "pass", "https://yourinstance.app.pheno.ml");

// After (option 1: env vars PHENOML_CLIENT_ID and PHENOML_CLIENT_SECRET)
PhenomlClient client = PhenomlClient.builder()
.url("https://yourinstance.app.pheno.ml")
.build();

// After (option 2: explicit credentials)
PhenomlClient client = PhenomlClient.builder()
.clientId("YOUR_CLIENT_ID")
.clientSecret("YOUR_CLIENT_SECRET")
.url("https://yourinstance.app.pheno.ml")
.build();
```

**Import updates:**

```java
// Before
import com.phenoml.api.Client;
// or
import com.phenoml.api.wrapper.PhenoMLClient;

// After
import com.phenoml.api.PhenomlClient;
```

### Added

- New `/v2/auth/token` OAuth 2.0 client credentials endpoint with `ClientCredentialsRequest`, `TokenResponse`, and `OAuthError` types.
- `OAuthTokenSupplier` for automatic token acquisition and caching.
- `InternalServerError` error type for authtoken module.

## 8.3.0 - 2026-03-03
* feat: add document multi-resource extraction endpoint
* Add a new endpoint for extracting multiple FHIR resources from documents (PDF/images).
Expand Down
77 changes: 77 additions & 0 deletions reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,83 @@ client.authtoken().auth().generateToken(
</dl>


</dd>
</dl>
</details>

<details><summary><code>client.authtoken.auth.getToken(request) -> TokenResponse</code></summary>
<dl>
<dd>

#### 📝 Description

<dl>
<dd>

<dl>
<dd>

OAuth 2.0 client credentials token endpoint (RFC 6749 §4.4).
Accepts client_id and client_secret in the request body (JSON or
form-encoded) or via Basic Auth header (RFC 6749 §2.3.1), and
returns an access token with expiration information.
</dd>
</dl>
</dd>
</dl>

#### 🔌 Usage

<dl>
<dd>

<dl>
<dd>

```java
client.authtoken().auth().getToken(
ClientCredentialsRequest
.builder()
.build()
);
```
</dd>
</dl>
</dd>
</dl>

#### ⚙️ Parameters

<dl>
<dd>

<dl>
<dd>

**grantType:** `Optional<String>` — Must be "client_credentials" if provided

</dd>
</dl>

<dl>
<dd>

**clientId:** `Optional<String>` — The client ID (credential username)

</dd>
</dl>

<dl>
<dd>

**clientSecret:** `Optional<String>` — The client secret (credential password)

</dd>
</dl>
</dd>
</dl>


</dd>
</dl>
</details>
Expand Down
2 changes: 1 addition & 1 deletion sample-app/src/main/java/sample/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@

public final class App {
public static void main(String[] args) {
// import com.phenoml.api.AsyncPhenoML
// import com.phenoml.api.AsyncPhenomlClient
}
}
38 changes: 0 additions & 38 deletions src/main/java/com/phenoml/api/AsyncClient.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import com.phenoml.api.resources.workflows.AsyncWorkflowsClient;
import java.util.function.Supplier;

public class AsyncPhenoML {
public class AsyncPhenomlClient {
protected final ClientOptions clientOptions;

protected final Supplier<AsyncAgentClient> agentClient;
Expand All @@ -40,7 +40,7 @@ public class AsyncPhenoML {

protected final Supplier<AsyncWorkflowsClient> workflowsClient;

public AsyncPhenoML(ClientOptions clientOptions) {
public AsyncPhenomlClient(ClientOptions clientOptions) {
this.clientOptions = clientOptions;
this.agentClient = Suppliers.memoize(() -> new AsyncAgentClient(clientOptions));
this.authtokenClient = Suppliers.memoize(() -> new AsyncAuthtokenClient(clientOptions));
Expand Down Expand Up @@ -94,7 +94,7 @@ public AsyncWorkflowsClient workflows() {
return this.workflowsClient.get();
}

public static AsyncPhenoMLBuilder builder() {
return new AsyncPhenoMLBuilder();
public static AsyncPhenomlClientBuilder builder() {
return new AsyncPhenomlClientBuilder();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,62 +5,76 @@

import com.phenoml.api.core.ClientOptions;
import com.phenoml.api.core.Environment;
import com.phenoml.api.core.OAuthTokenSupplier;
import com.phenoml.api.resources.authtoken.auth.AuthClient;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import okhttp3.OkHttpClient;

public class PhenoMLBuilder {
public class AsyncPhenomlClientBuilder {
private Optional<Integer> timeout = Optional.empty();

private Optional<Integer> maxRetries = Optional.empty();

private final Map<String, String> customHeaders = new HashMap<>();

private String token = null;
private String clientId = System.getenv("PHENOML_CLIENT_ID");

private String clientSecret = System.getenv("PHENOML_CLIENT_SECRET");

private Environment environment = Environment.DEFAULT;

private OkHttpClient httpClient;

/**
* Sets token
* Sets clientId.
* Defaults to the PHENOML_CLIENT_ID environment variable.
*/
public PhenoMLBuilder token(String token) {
this.token = token;
public AsyncPhenomlClientBuilder clientId(String clientId) {
this.clientId = clientId;
return this;
}

public PhenoMLBuilder environment(Environment environment) {
/**
* Sets clientSecret.
* Defaults to the PHENOML_CLIENT_SECRET environment variable.
*/
public AsyncPhenomlClientBuilder clientSecret(String clientSecret) {
this.clientSecret = clientSecret;
return this;
}

public AsyncPhenomlClientBuilder environment(Environment environment) {
this.environment = environment;
return this;
}

public PhenoMLBuilder url(String url) {
public AsyncPhenomlClientBuilder url(String url) {
this.environment = Environment.custom(url);
return this;
}

/**
* Sets the timeout (in seconds) for the client. Defaults to 60 seconds.
*/
public PhenoMLBuilder timeout(int timeout) {
public AsyncPhenomlClientBuilder timeout(int timeout) {
this.timeout = Optional.of(timeout);
return this;
}

/**
* Sets the maximum number of retries for the client. Defaults to 2 retries.
*/
public PhenoMLBuilder maxRetries(int maxRetries) {
public AsyncPhenomlClientBuilder maxRetries(int maxRetries) {
this.maxRetries = Optional.of(maxRetries);
return this;
}

/**
* Sets the underlying OkHttp client
*/
public PhenoMLBuilder httpClient(OkHttpClient httpClient) {
public AsyncPhenomlClientBuilder httpClient(OkHttpClient httpClient) {
this.httpClient = httpClient;
return this;
}
Expand All @@ -73,7 +87,7 @@ public PhenoMLBuilder httpClient(OkHttpClient httpClient) {
* @param value The header value
* @return This builder for method chaining
*/
public PhenoMLBuilder addHeader(String name, String value) {
public AsyncPhenomlClientBuilder addHeader(String name, String value) {
this.customHeaders.put(name, value);
return this;
}
Expand Down Expand Up @@ -118,8 +132,12 @@ protected void setEnvironment(ClientOptions.Builder builder) {
* }</pre>
*/
protected void setAuthentication(ClientOptions.Builder builder) {
if (this.token != null) {
builder.addHeader("Authorization", "Bearer " + this.token);
if (this.clientId != null && this.clientSecret != null) {
AuthClient authClient = new AuthClient(
ClientOptions.builder().environment(this.environment).build());
OAuthTokenSupplier oAuthTokenSupplier =
new OAuthTokenSupplier(this.clientId, this.clientSecret, authClient);
builder.addHeader("Authorization", oAuthTokenSupplier);
}
}

Expand Down Expand Up @@ -195,11 +213,8 @@ protected void setAdditional(ClientOptions.Builder builder) {}
*/
protected void validateConfiguration() {}

public PhenoML build() {
if (token == null) {
throw new RuntimeException("Please provide token");
}
public AsyncPhenomlClient build() {
validateConfiguration();
return new PhenoML(buildClientOptions());
return new AsyncPhenomlClient(buildClientOptions());
}
}
38 changes: 0 additions & 38 deletions src/main/java/com/phenoml/api/Client.java

This file was deleted.

Loading