diff --git a/README.md b/README.md
index 6fa0915..5e1b32a 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,74 @@
# Dfns Java SDK
-Java 17 SDK for the Dfns API.
+Welcome, builders. This repo holds the Dfns Java SDK. Useful links:
+
+- [Dfns Website](https://www.dfns.co)
+- [Dfns API Docs](https://docs.dfns.co)
+
+## Installation
+
+Requires **Java 17+**. The SDK is built with Gradle and will be published to Maven Central
+under group `co.dfns`, artifact `dfns-sdk-java`:
+
+**Gradle**
+
+```groovy
+implementation("co.dfns:dfns-sdk-java:$version")
+```
+
+**Maven**
+
+```xml
+
+ co.dfns
+ dfns-sdk-java
+ ${version}
+
+```
+
+> Maven Central publishing is being finalized; until it lands, build the SDK from source.
## Quick Start
```java
-import co.dfns.sdk.*;
-import co.dfns.sdk.auth.*;
+import co.dfns.sdk.DfnsClient;
+import co.dfns.sdk.DfnsClientConfig;
+
+// Create the client (read-only operations)
+DfnsClientConfig config = DfnsClientConfig.builder()
+ .authToken("your-auth-token")
+ // .baseUrl("https://api.dfns.io") // Optional, this is the default
+ .build();
-// Create a signer with your credential ID and private key
+DfnsClient client = new DfnsClient(config);
+
+// List wallets
+var wallets = client.wallets.listWallets(null);
+System.out.println(wallets);
+```
+
+An async client with the same API but `CompletableFuture` return types is also available:
+
+```java
+import co.dfns.sdk.DfnsAsyncClient;
+
+DfnsAsyncClient asyncClient = new DfnsAsyncClient(config);
+```
+
+## User Action Signing
+
+Some operations (like creating wallets or signing transactions) require user action signing.
+Configure a signer to enable these operations:
+
+```java
+import co.dfns.sdk.DfnsClient;
+import co.dfns.sdk.DfnsClientConfig;
+import co.dfns.sdk.auth.KeySigner;
+import co.dfns.sdk.auth.Signer;
+import co.dfns.sdk.wallets.model.CreateWalletRequest;
+import co.dfns.sdk.wallets.model.Network;
+
+// Create a signer from your credential ID and private key bytes
Signer signer = KeySigner.fromEd25519PrivateKey("cr-xxx-xxx", privateKeyBytes);
DfnsClientConfig config = DfnsClientConfig.builder()
@@ -17,9 +77,57 @@ DfnsClientConfig config = DfnsClientConfig.builder()
.build();
DfnsClient client = new DfnsClient(config);
-DfnsAsyncClient asyncClient = new DfnsAsyncClient(config);
+
+// Operations requiring signatures are signed automatically
+var wallet = client.wallets.createWallet(new CreateWalletRequest(Network.EthereumSepolia));
+System.out.println(wallet);
+```
+
+## Delegated Signing
+
+In some setups you want your **server** to talk to Dfns on behalf of a user, while the user
+keeps signing every request themselves (e.g. with a WebAuthn credential in a web app). The
+`DfnsDelegatedClient` supports this: it needs **no `Signer`**, and every operation that needs
+a user action signature is split into an `...Init` / `...Complete` pair.
+
+- `...Init` takes the request payload and returns a `UserActionChallenge` to be signed
+ out-of-band (typically by the end user in the browser).
+- `...Complete` takes the same payload, the challenge identifier, and the signed
+ `CredentialAssertion`, and performs the request.
+
+A typical flow: the server calls `...Init` and sends the challenge to the user; the user
+signs it with their credential and returns the assertion; the server calls `...Complete`.
+
+```java
+import co.dfns.sdk.DfnsClientConfig;
+import co.dfns.sdk.DfnsDelegatedClient;
+import co.dfns.sdk.auth.CredentialAssertion;
+import co.dfns.sdk.auth.UserActionChallenge;
+import co.dfns.sdk.wallets.model.CreateWalletRequest;
+import co.dfns.sdk.wallets.model.Network;
+
+// No signer needed — challenges are signed out-of-band (e.g. by the end user).
+DfnsClientConfig config = DfnsClientConfig.builder()
+ .authToken("user-auth-token")
+ .build();
+
+DfnsDelegatedClient client = new DfnsDelegatedClient(config);
+
+CreateWalletRequest body = new CreateWalletRequest(Network.EthereumSepolia);
+
+// Step 1 (server): start the action, get a challenge.
+UserActionChallenge challenge = client.wallets.createWalletInit(body);
+
+// Step 2 (client): the user signs `challenge` with their credential and returns the
+// signed assertion (a CredentialAssertion) to the server.
+CredentialAssertion assertion = signChallengeOutOfBand(challenge);
+
+// Step 3 (server): complete the action with the signed challenge.
+var wallet = client.wallets.createWalletComplete(body, challenge.challengeIdentifier(), assertion);
```
+A `DfnsDelegatedAsyncClient` with `CompletableFuture` return types is also available.
+
## Available Domains
- `client.agreements` — AgreementsClient
@@ -38,12 +146,35 @@ DfnsAsyncClient asyncClient = new DfnsAsyncClient(config);
- `client.wallets` — WalletsClient
- `client.webhooks` — WebhooksClient
+Each domain provides typed methods for all available API endpoints. The same domains are
+exposed (as `Delegated*Client`) on `DfnsDelegatedClient`.
+
## Error Handling
```java
+import co.dfns.sdk.DfnsException;
+
try {
- var result = client.wallets.listWallets();
+ var result = client.wallets.listWallets(null);
} catch (DfnsException e) {
System.err.println("HTTP status: " + e.getHttpStatus());
+ System.err.println("Dfns error code: " + e.getDfnsErrorCode());
+ System.err.println("Message: " + e.getErrorMessage());
}
```
+
+## Supported Key Types
+
+The `KeySigner` supports the following private key types, each via a factory method that
+takes the credential ID and the private key bytes:
+
+| Factory method | Key type |
+|---|---|
+| `KeySigner.fromEd25519PrivateKey` | Ed25519 (EdDSA) |
+| `KeySigner.fromEcdsaP256PrivateKey` | ECDSA (P-256) |
+| `KeySigner.fromSecp256k1PrivateKey` | ECDSA (secp256k1) |
+| `KeySigner.fromRsaPrivateKey` | RSA (PKCS#1 v1.5, SHA-256) |
+
+## License
+
+MIT License - See LICENSE file for details.
diff --git a/src/main/java/co/dfns/sdk/DfnsDelegatedAsyncClient.java b/src/main/java/co/dfns/sdk/DfnsDelegatedAsyncClient.java
new file mode 100644
index 0000000..e0d20f5
--- /dev/null
+++ b/src/main/java/co/dfns/sdk/DfnsDelegatedAsyncClient.java
@@ -0,0 +1,66 @@
+package co.dfns.sdk;
+
+import co.dfns.sdk.internal.DfnsHttpClient;
+import co.dfns.sdk.agreements.DelegatedAgreementsAsyncClient;
+import co.dfns.sdk.allocations.DelegatedAllocationsAsyncClient;
+import co.dfns.sdk.auth.DelegatedAuthAsyncClient;
+import co.dfns.sdk.exchanges.DelegatedExchangesAsyncClient;
+import co.dfns.sdk.feesponsors.DelegatedFeeSponsorsAsyncClient;
+import co.dfns.sdk.keys.DelegatedKeysAsyncClient;
+import co.dfns.sdk.networks.DelegatedNetworksAsyncClient;
+import co.dfns.sdk.payouts.DelegatedPayoutsAsyncClient;
+import co.dfns.sdk.permissions.DelegatedPermissionsAsyncClient;
+import co.dfns.sdk.policies.DelegatedPoliciesAsyncClient;
+import co.dfns.sdk.signers.DelegatedSignersAsyncClient;
+import co.dfns.sdk.staking.DelegatedStakingAsyncClient;
+import co.dfns.sdk.swaps.DelegatedSwapsAsyncClient;
+import co.dfns.sdk.wallets.DelegatedWalletsAsyncClient;
+import co.dfns.sdk.webhooks.DelegatedWebhooksAsyncClient;
+
+/**
+ * Dfns async SDK client for delegated user action signing. Its domain clients split signed
+ * operations into Init/Complete calls so challenges can be signed out-of-band (e.g. by an
+ * end user) rather than by a Signer held in this process.
+ */
+public class DfnsDelegatedAsyncClient implements AutoCloseable {
+ private final DfnsHttpClient httpClient;
+ public final DelegatedAgreementsAsyncClient agreements;
+ public final DelegatedAllocationsAsyncClient allocations;
+ public final DelegatedAuthAsyncClient auth;
+ public final DelegatedExchangesAsyncClient exchanges;
+ public final DelegatedFeeSponsorsAsyncClient feeSponsors;
+ public final DelegatedKeysAsyncClient keys;
+ public final DelegatedNetworksAsyncClient networks;
+ public final DelegatedPayoutsAsyncClient payouts;
+ public final DelegatedPermissionsAsyncClient permissions;
+ public final DelegatedPoliciesAsyncClient policies;
+ public final DelegatedSignersAsyncClient signers;
+ public final DelegatedStakingAsyncClient staking;
+ public final DelegatedSwapsAsyncClient swaps;
+ public final DelegatedWalletsAsyncClient wallets;
+ public final DelegatedWebhooksAsyncClient webhooks;
+
+ public DfnsDelegatedAsyncClient(DfnsClientConfig config) {
+ this.httpClient = new DfnsHttpClient(config);
+ this.agreements = new DelegatedAgreementsAsyncClient(httpClient);
+ this.allocations = new DelegatedAllocationsAsyncClient(httpClient);
+ this.auth = new DelegatedAuthAsyncClient(httpClient);
+ this.exchanges = new DelegatedExchangesAsyncClient(httpClient);
+ this.feeSponsors = new DelegatedFeeSponsorsAsyncClient(httpClient);
+ this.keys = new DelegatedKeysAsyncClient(httpClient);
+ this.networks = new DelegatedNetworksAsyncClient(httpClient);
+ this.payouts = new DelegatedPayoutsAsyncClient(httpClient);
+ this.permissions = new DelegatedPermissionsAsyncClient(httpClient);
+ this.policies = new DelegatedPoliciesAsyncClient(httpClient);
+ this.signers = new DelegatedSignersAsyncClient(httpClient);
+ this.staking = new DelegatedStakingAsyncClient(httpClient);
+ this.swaps = new DelegatedSwapsAsyncClient(httpClient);
+ this.wallets = new DelegatedWalletsAsyncClient(httpClient);
+ this.webhooks = new DelegatedWebhooksAsyncClient(httpClient);
+ }
+
+ @Override
+ public void close() {
+ httpClient.close();
+ }
+}
diff --git a/src/main/java/co/dfns/sdk/DfnsDelegatedClient.java b/src/main/java/co/dfns/sdk/DfnsDelegatedClient.java
new file mode 100644
index 0000000..1316114
--- /dev/null
+++ b/src/main/java/co/dfns/sdk/DfnsDelegatedClient.java
@@ -0,0 +1,66 @@
+package co.dfns.sdk;
+
+import co.dfns.sdk.internal.DfnsHttpClient;
+import co.dfns.sdk.agreements.DelegatedAgreementsClient;
+import co.dfns.sdk.allocations.DelegatedAllocationsClient;
+import co.dfns.sdk.auth.DelegatedAuthClient;
+import co.dfns.sdk.exchanges.DelegatedExchangesClient;
+import co.dfns.sdk.feesponsors.DelegatedFeeSponsorsClient;
+import co.dfns.sdk.keys.DelegatedKeysClient;
+import co.dfns.sdk.networks.DelegatedNetworksClient;
+import co.dfns.sdk.payouts.DelegatedPayoutsClient;
+import co.dfns.sdk.permissions.DelegatedPermissionsClient;
+import co.dfns.sdk.policies.DelegatedPoliciesClient;
+import co.dfns.sdk.signers.DelegatedSignersClient;
+import co.dfns.sdk.staking.DelegatedStakingClient;
+import co.dfns.sdk.swaps.DelegatedSwapsClient;
+import co.dfns.sdk.wallets.DelegatedWalletsClient;
+import co.dfns.sdk.webhooks.DelegatedWebhooksClient;
+
+/**
+ * Dfns SDK client for delegated user action signing. Its domain clients split signed
+ * operations into Init/Complete calls so challenges can be signed out-of-band (e.g. by an
+ * end user) rather than by a Signer held in this process.
+ */
+public class DfnsDelegatedClient implements AutoCloseable {
+ private final DfnsHttpClient httpClient;
+ public final DelegatedAgreementsClient agreements;
+ public final DelegatedAllocationsClient allocations;
+ public final DelegatedAuthClient auth;
+ public final DelegatedExchangesClient exchanges;
+ public final DelegatedFeeSponsorsClient feeSponsors;
+ public final DelegatedKeysClient keys;
+ public final DelegatedNetworksClient networks;
+ public final DelegatedPayoutsClient payouts;
+ public final DelegatedPermissionsClient permissions;
+ public final DelegatedPoliciesClient policies;
+ public final DelegatedSignersClient signers;
+ public final DelegatedStakingClient staking;
+ public final DelegatedSwapsClient swaps;
+ public final DelegatedWalletsClient wallets;
+ public final DelegatedWebhooksClient webhooks;
+
+ public DfnsDelegatedClient(DfnsClientConfig config) {
+ this.httpClient = new DfnsHttpClient(config);
+ this.agreements = new DelegatedAgreementsClient(httpClient);
+ this.allocations = new DelegatedAllocationsClient(httpClient);
+ this.auth = new DelegatedAuthClient(httpClient);
+ this.exchanges = new DelegatedExchangesClient(httpClient);
+ this.feeSponsors = new DelegatedFeeSponsorsClient(httpClient);
+ this.keys = new DelegatedKeysClient(httpClient);
+ this.networks = new DelegatedNetworksClient(httpClient);
+ this.payouts = new DelegatedPayoutsClient(httpClient);
+ this.permissions = new DelegatedPermissionsClient(httpClient);
+ this.policies = new DelegatedPoliciesClient(httpClient);
+ this.signers = new DelegatedSignersClient(httpClient);
+ this.staking = new DelegatedStakingClient(httpClient);
+ this.swaps = new DelegatedSwapsClient(httpClient);
+ this.wallets = new DelegatedWalletsClient(httpClient);
+ this.webhooks = new DelegatedWebhooksClient(httpClient);
+ }
+
+ @Override
+ public void close() {
+ httpClient.close();
+ }
+}
diff --git a/src/main/java/co/dfns/sdk/agreements/DelegatedAgreementsAsyncClient.java b/src/main/java/co/dfns/sdk/agreements/DelegatedAgreementsAsyncClient.java
new file mode 100644
index 0000000..b6a05b2
--- /dev/null
+++ b/src/main/java/co/dfns/sdk/agreements/DelegatedAgreementsAsyncClient.java
@@ -0,0 +1,32 @@
+package co.dfns.sdk.agreements;
+
+import co.dfns.sdk.internal.DfnsHttpClient;
+import co.dfns.sdk.agreements.model.*;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import co.dfns.sdk.auth.UserActionChallenge;
+import co.dfns.sdk.auth.CredentialAssertion;
+
+public class DelegatedAgreementsAsyncClient {
+ private final DfnsHttpClient httpClient;
+
+ public DelegatedAgreementsAsyncClient(DfnsHttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
+
+ /** Get Latest Unaccepted Agreement */
+ public CompletableFuture getLatestUnacceptedAgreement(GetLatestUnacceptedAgreementQuery query) {
+ return httpClient.getAsync("/agreements/latest-unaccepted", query.toMap(), GetLatestUnacceptedAgreementResponse.class);
+ }
+
+ /** Delegated signing step 1 for Record Agreement Acceptance: returns the challenge to sign out-of-band. */
+ public CompletableFuture recordAgreementAcceptanceInit(String agreementId) {
+ return httpClient.createUserActionChallengeAsync("POST", "/agreements/" + agreementId + "/accept", null);
+ }
+
+ /** Delegated signing step 2 for Record Agreement Acceptance: submits the signed challenge and issues the request. */
+ public CompletableFuture recordAgreementAcceptanceComplete(String agreementId, String challengeIdentifier, CredentialAssertion assertion) {
+ return httpClient.completeUserActionSigningAsync(challengeIdentifier, assertion)
+ .thenCompose(userAction -> httpClient.executeWithUserActionAsync("POST", "/agreements/" + agreementId + "/accept", java.util.Map.of(), null, RecordAgreementAcceptanceResponse.class, userAction));
+ }
+}
diff --git a/src/main/java/co/dfns/sdk/agreements/DelegatedAgreementsClient.java b/src/main/java/co/dfns/sdk/agreements/DelegatedAgreementsClient.java
new file mode 100644
index 0000000..c67b273
--- /dev/null
+++ b/src/main/java/co/dfns/sdk/agreements/DelegatedAgreementsClient.java
@@ -0,0 +1,31 @@
+package co.dfns.sdk.agreements;
+
+import co.dfns.sdk.internal.DfnsHttpClient;
+import co.dfns.sdk.agreements.model.*;
+import java.util.Map;
+import co.dfns.sdk.auth.UserActionChallenge;
+import co.dfns.sdk.auth.CredentialAssertion;
+
+public class DelegatedAgreementsClient {
+ private final DfnsHttpClient httpClient;
+
+ public DelegatedAgreementsClient(DfnsHttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
+
+ /** Get Latest Unaccepted Agreement */
+ public GetLatestUnacceptedAgreementResponse getLatestUnacceptedAgreement(GetLatestUnacceptedAgreementQuery query) {
+ return httpClient.get("/agreements/latest-unaccepted", query.toMap(), GetLatestUnacceptedAgreementResponse.class);
+ }
+
+ /** Delegated signing step 1 for Record Agreement Acceptance: returns the challenge to sign out-of-band. */
+ public UserActionChallenge recordAgreementAcceptanceInit(String agreementId) {
+ return httpClient.createUserActionChallenge("POST", "/agreements/" + agreementId + "/accept", null);
+ }
+
+ /** Delegated signing step 2 for Record Agreement Acceptance: submits the signed challenge and issues the request. */
+ public RecordAgreementAcceptanceResponse recordAgreementAcceptanceComplete(String agreementId, String challengeIdentifier, CredentialAssertion assertion) {
+ String userAction = httpClient.completeUserActionSigning(challengeIdentifier, assertion);
+ return httpClient.executeWithUserAction("POST", "/agreements/" + agreementId + "/accept", java.util.Map.of(), null, RecordAgreementAcceptanceResponse.class, userAction);
+ }
+}
diff --git a/src/main/java/co/dfns/sdk/allocations/DelegatedAllocationsAsyncClient.java b/src/main/java/co/dfns/sdk/allocations/DelegatedAllocationsAsyncClient.java
new file mode 100644
index 0000000..065cc37
--- /dev/null
+++ b/src/main/java/co/dfns/sdk/allocations/DelegatedAllocationsAsyncClient.java
@@ -0,0 +1,54 @@
+package co.dfns.sdk.allocations;
+
+import co.dfns.sdk.internal.DfnsHttpClient;
+import co.dfns.sdk.allocations.model.*;
+import java.util.List;
+import co.dfns.sdk.PaginatedList;
+import java.util.concurrent.CompletableFuture;
+import co.dfns.sdk.auth.UserActionChallenge;
+import co.dfns.sdk.auth.CredentialAssertion;
+
+public class DelegatedAllocationsAsyncClient {
+ private final DfnsHttpClient httpClient;
+
+ public DelegatedAllocationsAsyncClient(DfnsHttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
+
+ /** List Allocations */
+ public CompletableFuture> listAllocations(ListAllocationsQuery query) {
+ return httpClient.getAsync("/allocations", query.toMap(), new com.fasterxml.jackson.core.type.TypeReference>() {});
+ }
+
+ /** Delegated signing step 1 for Create Allocation: returns the challenge to sign out-of-band. */
+ public CompletableFuture createAllocationInit(Object body) {
+ return httpClient.createUserActionChallengeAsync("POST", "/allocations", body);
+ }
+
+ /** Delegated signing step 2 for Create Allocation: submits the signed challenge and issues the request. */
+ public CompletableFuture createAllocationComplete(Object body, String challengeIdentifier, CredentialAssertion assertion) {
+ return httpClient.completeUserActionSigningAsync(challengeIdentifier, assertion)
+ .thenCompose(userAction -> httpClient.executeWithUserActionAsync("POST", "/allocations", java.util.Map.of(), body, Allocation.class, userAction));
+ }
+
+ /** List Allocation Actions */
+ public CompletableFuture> listAllocationActions(String allocationId, ListAllocationActionsQuery query) {
+ return httpClient.getAsync("/allocations/" + allocationId + "/actions", query.toMap(), new com.fasterxml.jackson.core.type.TypeReference>() {});
+ }
+
+ /** Delegated signing step 1 for Create Allocation Action: returns the challenge to sign out-of-band. */
+ public CompletableFuture createAllocationActionInit(String allocationId, Object body) {
+ return httpClient.createUserActionChallengeAsync("POST", "/allocations/" + allocationId + "/actions", body);
+ }
+
+ /** Delegated signing step 2 for Create Allocation Action: submits the signed challenge and issues the request. */
+ public CompletableFuture createAllocationActionComplete(String allocationId, Object body, String challengeIdentifier, CredentialAssertion assertion) {
+ return httpClient.completeUserActionSigningAsync(challengeIdentifier, assertion)
+ .thenCompose(userAction -> httpClient.executeWithUserActionAsync("POST", "/allocations/" + allocationId + "/actions", java.util.Map.of(), body, Allocation.class, userAction));
+ }
+
+ /** Get Allocation */
+ public CompletableFuture getAllocation(String allocationId) {
+ return httpClient.getAsync("/allocations/" + allocationId, java.util.Map.of(), Allocation.class);
+ }
+}
diff --git a/src/main/java/co/dfns/sdk/allocations/DelegatedAllocationsClient.java b/src/main/java/co/dfns/sdk/allocations/DelegatedAllocationsClient.java
new file mode 100644
index 0000000..27111c0
--- /dev/null
+++ b/src/main/java/co/dfns/sdk/allocations/DelegatedAllocationsClient.java
@@ -0,0 +1,53 @@
+package co.dfns.sdk.allocations;
+
+import co.dfns.sdk.internal.DfnsHttpClient;
+import co.dfns.sdk.allocations.model.*;
+import java.util.List;
+import co.dfns.sdk.PaginatedList;
+import co.dfns.sdk.auth.UserActionChallenge;
+import co.dfns.sdk.auth.CredentialAssertion;
+
+public class DelegatedAllocationsClient {
+ private final DfnsHttpClient httpClient;
+
+ public DelegatedAllocationsClient(DfnsHttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
+
+ /** List Allocations */
+ public PaginatedList listAllocations(ListAllocationsQuery query) {
+ return httpClient.get("/allocations", query.toMap(), new com.fasterxml.jackson.core.type.TypeReference>() {});
+ }
+
+ /** Delegated signing step 1 for Create Allocation: returns the challenge to sign out-of-band. */
+ public UserActionChallenge createAllocationInit(Object body) {
+ return httpClient.createUserActionChallenge("POST", "/allocations", body);
+ }
+
+ /** Delegated signing step 2 for Create Allocation: submits the signed challenge and issues the request. */
+ public Allocation createAllocationComplete(Object body, String challengeIdentifier, CredentialAssertion assertion) {
+ String userAction = httpClient.completeUserActionSigning(challengeIdentifier, assertion);
+ return httpClient.executeWithUserAction("POST", "/allocations", java.util.Map.of(), body, Allocation.class, userAction);
+ }
+
+ /** List Allocation Actions */
+ public PaginatedList listAllocationActions(String allocationId, ListAllocationActionsQuery query) {
+ return httpClient.get("/allocations/" + allocationId + "/actions", query.toMap(), new com.fasterxml.jackson.core.type.TypeReference>() {});
+ }
+
+ /** Delegated signing step 1 for Create Allocation Action: returns the challenge to sign out-of-band. */
+ public UserActionChallenge createAllocationActionInit(String allocationId, Object body) {
+ return httpClient.createUserActionChallenge("POST", "/allocations/" + allocationId + "/actions", body);
+ }
+
+ /** Delegated signing step 2 for Create Allocation Action: submits the signed challenge and issues the request. */
+ public Allocation createAllocationActionComplete(String allocationId, Object body, String challengeIdentifier, CredentialAssertion assertion) {
+ String userAction = httpClient.completeUserActionSigning(challengeIdentifier, assertion);
+ return httpClient.executeWithUserAction("POST", "/allocations/" + allocationId + "/actions", java.util.Map.of(), body, Allocation.class, userAction);
+ }
+
+ /** Get Allocation */
+ public Allocation getAllocation(String allocationId) {
+ return httpClient.get("/allocations/" + allocationId, java.util.Map.of(), Allocation.class);
+ }
+}
diff --git a/src/main/java/co/dfns/sdk/auth/DelegatedAuthAsyncClient.java b/src/main/java/co/dfns/sdk/auth/DelegatedAuthAsyncClient.java
new file mode 100644
index 0000000..057905e
--- /dev/null
+++ b/src/main/java/co/dfns/sdk/auth/DelegatedAuthAsyncClient.java
@@ -0,0 +1,446 @@
+package co.dfns.sdk.auth;
+
+import co.dfns.sdk.internal.DfnsHttpClient;
+import co.dfns.sdk.auth.model.*;
+import java.util.Map;
+import java.util.List;
+import co.dfns.sdk.PaginatedList;
+import java.util.concurrent.CompletableFuture;
+import co.dfns.sdk.auth.UserActionChallenge;
+import co.dfns.sdk.auth.CredentialAssertion;
+
+public class DelegatedAuthAsyncClient {
+ private final DfnsHttpClient httpClient;
+
+ public DelegatedAuthAsyncClient(DfnsHttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
+
+ /** Create User Action Signature */
+ public CompletableFuture createUserActionSignature(CreateUserActionSignatureRequest body) {
+ return httpClient.postAsync("/auth/action", java.util.Map.of(), body, CreateUserActionSignatureResponse.class, false);
+ }
+
+ /** Create User Action Challenge */
+ public CompletableFuture createUserActionChallenge(CreateUserActionChallengeRequest body) {
+ return httpClient.postAsync("/auth/action/init", java.util.Map.of(), body, CreateUserActionChallengeResponse.class, false);
+ }
+
+ /** List Audit Logs */
+ public CompletableFuture