diff --git a/docker-compose.yaml b/docker-compose.yaml
index 31a083c..1e3c816 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -6,8 +6,8 @@ services:
volumes:
- .:/app
working_dir: /app
- # Run only unit tests (no real credentials). Full suite: mvn test with env set.
- command: mvn test -Dtest=ProjectsClientTest,AwsAuthProviderTest
+ # Run only unit tests (no real credentials). Full suite: mvn test -q with env set.
+ command: mvn test -Dtest=RevokeTokenInputTest,AuthClientTest,AwsAuthProviderTest,ProjectsClientTest
format:
image: cimg/openjdk:21.0
diff --git a/pom.xml b/pom.xml
index 024aa82..ac061ec 100644
--- a/pom.xml
+++ b/pom.xml
@@ -154,13 +154,13 @@
org.mockito
mockito-core
- 5.5.0
+ 5.8.0
test
org.mockito
mockito-junit-jupiter
- 5.5.0
+ 5.8.0
test
diff --git a/src/main/java/com/infisical/sdk/api/ApiClient.java b/src/main/java/com/infisical/sdk/api/ApiClient.java
index e417240..ae9e5cb 100644
--- a/src/main/java/com/infisical/sdk/api/ApiClient.java
+++ b/src/main/java/com/infisical/sdk/api/ApiClient.java
@@ -5,6 +5,7 @@
import com.squareup.okhttp.*;
import com.squareup.okhttp.Request;
import java.io.IOException;
+import java.util.Collections;
import java.util.Map;
public class ApiClient {
@@ -95,6 +96,14 @@ public R post(String url, T requestBody, Class responseType) throws In
}
String responseJson = responseBody.string();
+ if (responseJson == null || responseJson.trim().isEmpty()) {
+ return null;
+ }
+
+ if (responseType == Void.class) {
+ return null;
+ }
+
return gson.fromJson(responseJson, responseType);
}
} catch (IOException e) {
@@ -102,6 +111,11 @@ public R post(String url, T requestBody, Class responseType) throws In
}
}
+ /** POST with empty JSON body. Delegates to {@link #post(String, Object, Class)}. */
+ public R post(String url, Class responseType) throws InfisicalException {
+ return post(url, Collections.emptyMap(), responseType);
+ }
+
public R get(String baseUrl, Map queryParams, Class responseType)
throws InfisicalException {
try {
diff --git a/src/main/java/com/infisical/sdk/models/RevokeTokenInput.java b/src/main/java/com/infisical/sdk/models/RevokeTokenInput.java
new file mode 100644
index 0000000..abbd135
--- /dev/null
+++ b/src/main/java/com/infisical/sdk/models/RevokeTokenInput.java
@@ -0,0 +1,20 @@
+package com.infisical.sdk.models;
+
+import com.google.gson.annotations.SerializedName;
+import com.infisical.sdk.util.Helper;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class RevokeTokenInput {
+ @SerializedName("accessToken")
+ private String accessToken;
+
+ public String validate() {
+ if (Helper.isNullOrEmpty(accessToken)) {
+ return "Access token is required";
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/infisical/sdk/resources/AuthClient.java b/src/main/java/com/infisical/sdk/resources/AuthClient.java
index 38cac5d..b74ce92 100644
--- a/src/main/java/com/infisical/sdk/resources/AuthClient.java
+++ b/src/main/java/com/infisical/sdk/resources/AuthClient.java
@@ -5,6 +5,7 @@
import com.infisical.sdk.models.AwsAuthLoginInput;
import com.infisical.sdk.models.LdapAuthLoginInput;
import com.infisical.sdk.models.MachineIdentityCredential;
+import com.infisical.sdk.models.RevokeTokenInput;
import com.infisical.sdk.models.UniversalAuthLoginInput;
import com.infisical.sdk.util.InfisicalException;
import java.util.function.Consumer;
@@ -58,4 +59,16 @@ public void AwsAuthLogin(AwsAuthLoginInput input) throws InfisicalException {
public void SetAccessToken(String accessToken) {
this.onAuthenticate.accept(accessToken);
}
+
+ public void RevokeToken(String accessToken) throws InfisicalException {
+ RevokeTokenInput input = RevokeTokenInput.builder().accessToken(accessToken).build();
+
+ String validationMsg = input.validate();
+ if (validationMsg != null) {
+ throw new InfisicalException(validationMsg);
+ }
+
+ String url = String.format("%s%s", this.apiClient.GetBaseUrl(), "/api/v1/auth/token/revoke");
+ this.apiClient.post(url, input, Void.class);
+ }
}
diff --git a/src/test/java/com/infisical/sdk/models/RevokeTokenInputTest.java b/src/test/java/com/infisical/sdk/models/RevokeTokenInputTest.java
new file mode 100644
index 0000000..cd467f7
--- /dev/null
+++ b/src/test/java/com/infisical/sdk/models/RevokeTokenInputTest.java
@@ -0,0 +1,33 @@
+package com.infisical.sdk.models;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class RevokeTokenInputTest {
+
+ @Test
+ public void validate_returnsNull_whenAccessTokenIsSet() {
+ RevokeTokenInput input = RevokeTokenInput.builder().accessToken("token-123").build();
+ assertNull(input.validate());
+ }
+
+ @Test
+ public void validate_returnsMessage_whenAccessTokenIsNull() {
+ RevokeTokenInput input = RevokeTokenInput.builder().accessToken(null).build();
+ assertNotNull(input.validate());
+ }
+
+ @Test
+ public void validate_returnsMessage_whenAccessTokenIsEmpty() {
+ RevokeTokenInput input = RevokeTokenInput.builder().accessToken("").build();
+ assertNotNull(input.validate());
+ }
+
+ @Test
+ public void validate_returnsMessage_whenAccessTokenIsWhitespace() {
+ RevokeTokenInput input = RevokeTokenInput.builder().accessToken(" ").build();
+ assertNotNull(input.validate());
+ }
+}
diff --git a/src/test/java/com/infisical/sdk/resources/AuthClientTest.java b/src/test/java/com/infisical/sdk/resources/AuthClientTest.java
new file mode 100644
index 0000000..8fcef82
--- /dev/null
+++ b/src/test/java/com/infisical/sdk/resources/AuthClientTest.java
@@ -0,0 +1,52 @@
+package com.infisical.sdk.resources;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.infisical.sdk.api.ApiClient;
+import com.infisical.sdk.models.RevokeTokenInput;
+import com.infisical.sdk.util.InfisicalException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public class AuthClientTest {
+
+ @Mock
+ private ApiClient apiClient;
+
+ @Test
+ public void RevokeToken_throwsWhenAccessTokenIsNull() {
+ AuthClient authClient = new AuthClient(apiClient, token -> {});
+
+ InfisicalException ex = assertThrows(InfisicalException.class, () -> authClient.RevokeToken(null));
+ assertEquals("Access token is required", ex.getMessage());
+ }
+
+ @Test
+ public void RevokeToken_throwsWhenAccessTokenIsEmpty() {
+ AuthClient authClient = new AuthClient(apiClient, token -> {});
+
+ InfisicalException ex = assertThrows(InfisicalException.class, () -> authClient.RevokeToken(""));
+ assertEquals("Access token is required", ex.getMessage());
+ }
+
+ @Test
+ public void RevokeToken_callsPostWithCorrectUrlAndBody() throws InfisicalException {
+ when(apiClient.GetBaseUrl()).thenReturn("http://localhost");
+ AuthClient authClient = new AuthClient(apiClient, token -> {});
+
+ authClient.RevokeToken("token-123");
+
+ verify(apiClient).post(
+ eq("http://localhost/api/v1/auth/token/revoke"),
+ any(RevokeTokenInput.class),
+ eq(Void.class));
+ }
+}