Java 17 SDK in sdk-java/: - AgentIdPClient composing AgentRegistryClient, CredentialClient, TokenClient, AuditClient — all 14 endpoints covered - Both sync methods and CompletableFuture<T> async counterparts on each client - Thread-safe TokenManager (synchronized) with 60s refresh buffer - AgentIdPException (extends RuntimeException) with Code/HTTPStatus/Details - Builder pattern for all request types; Jackson 2.17 for JSON - Zero external HTTP dependencies — java.net.http.HttpClient (Java 11+) - No-dep JDK HttpServer used for unit tests (no WireMock needed) - mvn verify: 49/49 tests passed | JaCoCo coverage gate: >80% ✓ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SentryAgent.ai AgentIdP — Java SDK
Official Java client for the SentryAgent.ai AgentIdP — an open-source Identity Provider for AI agents built on OAuth 2.0 (RFC 6749) and aligned with the AGNTCY open standard.
Requirements
- Java 17+
- A running AgentIdP server
Installation
Maven
<dependency>
<groupId>ai.sentryagent</groupId>
<artifactId>idp-sdk</artifactId>
<version>1.0.0</version>
</dependency>
Quick Start
import ai.sentryagent.idp.AgentIdPClient;
import ai.sentryagent.idp.models.*;
AgentIdPClient client = new AgentIdPClient(
"https://idp.example.com",
"your-agent-client-id",
"sk_live_..."
);
// Register a new AI agent
Agent agent = client.agents().registerAgent(
RegisterAgentRequest.builder()
.email("screener@example.com")
.agentType("screener")
.version("1.0.0")
.capabilities(List.of("read", "classify"))
.owner("platform-team")
.deploymentEnv("production")
.build()
);
System.out.println("Registered: " + agent.getAgentId());
Authentication
OAuth 2.0 Client Credentials are managed automatically. Tokens are cached and refreshed 60 seconds before expiry. The TokenManager is thread-safe.
// Custom scope (optional — defaults to all four scopes)
AgentIdPClient client = new AgentIdPClient(
"https://idp.example.com",
"my-client-id",
"my-client-secret",
"agents:read agents:write"
);
Agent Registry
// Register
Agent agent = client.agents().registerAgent(
RegisterAgentRequest.builder()
.email("...").agentType("screener").version("1.0.0")
.capabilities(List.of("read")).owner("team").deploymentEnv("production")
.build());
// List (with optional filters)
PaginatedAgents agents = client.agents().listAgents(
ListAgentsParams.builder().status("active").page(1).limit(20).build());
// Get by ID
Agent agent = client.agents().getAgent("agent-uuid");
// Partial update
Agent updated = client.agents().updateAgent("agent-uuid",
UpdateAgentRequest.builder().version("2.0.0").build());
// Decommission (permanent)
client.agents().decommissionAgent("agent-uuid");
Credential Management
// Generate (returns one-time ClientSecret)
CredentialWithSecret cred = client.credentials().generateCredential("agent-uuid");
System.out.println(cred.getClientSecret()); // store this — shown only once
// List
PaginatedCredentials creds = client.credentials().listCredentials("agent-uuid", 1, 20);
// Rotate
CredentialWithSecret newCred = client.credentials().rotateCredential("agent-uuid", "cred-uuid");
// Revoke
Credential revoked = client.credentials().revokeCredential("agent-uuid", "cred-uuid");
Token Operations
// Introspect (RFC 7662)
IntrospectResponse result = client.tokens().introspectToken("access-token-to-check");
if (result.isActive()) {
System.out.println("Token belongs to: " + result.getSub());
}
// Revoke
client.tokens().revokeToken("access-token-to-revoke");
Audit Log
// Query with filters
PaginatedAuditEvents events = client.audit().queryAuditLog(
QueryAuditParams.builder()
.agentId("agent-uuid")
.action("token.issued")
.outcome("success")
.fromDate("2026-01-01")
.toDate("2026-01-31")
.page(1).limit(50)
.build());
// Get single event
AuditEvent event = client.audit().getAuditEvent("event-uuid");
Async Methods
Every sync method has an async counterpart returning CompletableFuture<T>:
CompletableFuture<Agent> future = client.agents().getAgentAsync("uuid-1");
future.thenAccept(agent -> System.out.println(agent.getAgentId()));
// Compose multiple async calls
client.agents().getAgentAsync("uuid-1")
.thenCompose(agent -> client.credentials().generateCredentialAsync(agent.getAgentId()))
.thenAccept(cred -> System.out.println("New secret: " + cred.getClientSecret()));
Error Handling
All errors are thrown as AgentIdPException (extends RuntimeException):
try {
Agent agent = client.agents().getAgent("unknown-id");
} catch (AgentIdPException ex) {
System.out.printf("code=%s status=%d%n", ex.getCode(), ex.getHttpStatus());
// e.g. code=AgentNotFoundError status=404
}
| Method | Type | Description |
|---|---|---|
getCode() |
String |
Machine-readable error code |
getMessage() |
String |
Human-readable description |
getHttpStatus() |
int |
HTTP status code (0 for network/build errors) |
getDetails() |
Map<String, Object> |
Optional structured context from the API |
API Coverage
| Endpoint | Method | SDK Method |
|---|---|---|
| POST /api/v1/agents | POST | agents().registerAgent() |
| GET /api/v1/agents | GET | agents().listAgents() |
| GET /api/v1/agents/:id | GET | agents().getAgent() |
| PATCH /api/v1/agents/:id | PATCH | agents().updateAgent() |
| DELETE /api/v1/agents/:id | DELETE | agents().decommissionAgent() |
| POST /api/v1/agents/:id/credentials | POST | credentials().generateCredential() |
| GET /api/v1/agents/:id/credentials | GET | credentials().listCredentials() |
| POST /api/v1/agents/:id/credentials/:cid/rotate | POST | credentials().rotateCredential() |
| DELETE /api/v1/agents/:id/credentials/:cid | DELETE | credentials().revokeCredential() |
| POST /api/v1/token | POST | (TokenManager — automatic) |
| POST /api/v1/token/introspect | POST | tokens().introspectToken() |
| POST /api/v1/token/revoke | POST | tokens().revokeToken() |
| GET /api/v1/audit | GET | audit().queryAuditLog() |
| GET /api/v1/audit/:id | GET | audit().getAuditEvent() |
License
Apache 2.0 — see LICENSE.