Cryptographic identity, capability authorization, and audit trails for Java AI agents. Apache 2.0.
Part of Agent Identity Management (AIM). Managed hosting at aim.opena2a.org/get-started; self-host via the main README.
import org.opena2a.aim.client.AIMClient;
AIMClient agent = AIMClient.secure("my-first-agent");
User user = agent.performAction("db:read", "users_table", () ->
userRepository.findById(userId)
);secure() generates an Ed25519 keypair, registers the agent, and stores credentials at ~/.aim/. performAction() signs every invocation, has the server check it against the capabilities granted to the agent and the organization's security policies, and records the outcome in the audit log. The server's 5-step Fine-Grained Authorization engine does not decide these calls; it runs on POST /api/v1/agents/:id/authorize, which the SDK does not call.
For declarative security, use @SecureAction with AspectJ:
import org.opena2a.aim.annotations.SecureAction;
import org.opena2a.aim.client.RiskLevel;
public class UserService {
@SecureAction(capability = "db:read", resource = "users_table")
public User getUserById(String id) {
return userRepository.findById(id);
}
@SecureAction(capability = "payment:process", riskLevel = RiskLevel.HIGH)
public PaymentResult processPayment(PaymentRequest request) {
return paymentService.process(request);
}
}The SDK is not on Maven Central. Build it from source, from the repository root:
cd sdk/java
mvn installmvn install compiles the SDK, runs its tests and places org.opena2a:aim-sdk:1.0.0 in your local Maven repository. Then add the dependency to your pom.xml:
<dependency>
<groupId>org.opena2a</groupId>
<artifactId>aim-sdk</artifactId>
<version>1.0.0</version>
</dependency>The SDK reads credentials from environment variables first, then ~/.aim/sdk_credentials.json.
export AIM_URL=https://aim.opena2a.org
export AIM_CLIENT_ID=your-client-id
export AIM_CLIENT_SECRET=your-client-secret
export AIM_ORG_ID=your-org-idOr place a credentials file at ~/.aim/sdk_credentials.json (mode 0600):
{
"aimUrl": "https://aim.opena2a.org",
"clientId": "your-client-id",
"clientSecret": "your-client-secret",
"organizationId": "your-org-id"
}To download pre-configured credentials: log in to the AIM dashboard, go to Settings → SDK Download, copy the JSON into ~/.aim/sdk_credentials.json.
// Auto-detected agent type
AIMClient agent = AIMClient.secure("my-agent");
// With declared capabilities and explicit agent type
AIMClient agent = AIMClient.secure(
"my-agent",
Arrays.asList("db:read", "api:call", "email:send"),
AgentType.CUSTOM
);// Pre-check without executing
VerificationResult result = agent.verifyCapability("db:read", "users_table");
if (result.isVerified()) {
User user = userRepository.findById(userId);
} else {
System.err.println("Denied: " + result.getStatus());
}
// Execute with automatic verification
User user = agent.performAction("db:read", "users_table", () ->
userRepository.findById(userId)
);
// Explicit risk level
PaymentResult payment = agent.performAction(
"payment:process", "stripe_api", RiskLevel.HIGH,
() -> paymentService.process(request)
);Wire the aspect once at startup:
import org.opena2a.aim.annotations.SecureActionAspect;
AIMClient agent = AIMClient.secure("my-agent");
SecureActionAspect.setClient(agent);Then annotate methods:
@SecureAction(
capability = "db:delete",
resource = "users_table",
riskLevel = RiskLevel.CRITICAL,
jitAccess = true,
jitTimeout = 300
)
public void deleteUser(String userId) {
userRepository.deleteById(userId);
}For Spring Boot:
@Configuration
@EnableAspectJAutoProxy
public class SecurityConfig {
@Bean
public AIMClient aimClient() {
return AIMClient.secure("my-spring-agent");
}
@PostConstruct
public void configureAspect() {
SecureActionAspect.setClient(aimClient());
}
}| Level | Approval | When to use |
|---|---|---|
LOW |
None | Read operations, safe actions |
MEDIUM |
None | Write operations, data modification |
HIGH |
None unless jitAccess |
Sensitive operations |
CRITICAL |
jitAccess = true |
Destructive operations |
jitAccess = true pauses execution and creates an approval request in the AIM dashboard. The method returns only after a human approves, or throws JITAccessTimeoutException after jitTimeout seconds.
import org.opena2a.aim.integrations.mcp.MCPIntegration;
import org.opena2a.aim.integrations.mcp.MCPServerInfo;
// Register an MCP server
MCPServerInfo server = MCPIntegration.registerServer(
agent,
"filesystem-mcp",
"http://localhost:3000",
publicKeyBase64,
Arrays.asList("read_file", "write_file", "list_directory")
);
// Record tool usage for supply-chain analytics
MCPIntegration.recordToolUsage(agent, server.getId(), "read_file");Map<String, Object> result = agent.requestCapability(
"db:delete",
"Need to implement user account deletion feature"
);
String status = (String) result.get("status");
if ("pending".equals(status)) {
// Awaiting admin approval in the dashboard
}For full control over configuration:
AIMClient agent = new AIMClient.Builder()
.agentName("my-enterprise-agent")
.aimUrl("https://aim.mycompany.com")
.clientId("client-id")
.clientSecret("client-secret")
.organizationId("org-id")
.agentType(AgentType.LANGCHAIN)
.addCapability("db:read")
.addCapability("db:write")
.build();import org.opena2a.aim.exceptions.*;
try {
agent.performAction("db:delete", "users", () -> deleteAllUsers());
} catch (ActionDeniedException e) {
// Capability denied — capability + resource available via getters
} catch (VerificationException e) {
// Signature or trust-score check failed
} catch (AuthenticationException e) {
// Credentials missing or invalid
} catch (CredentialException e) {
// Cannot load credentials from disk
} catch (AIMException e) {
// Any other AIM error
}The SDK loads credentials in this order:
- Environment variables (
AIM_URL,AIM_CLIENT_ID,AIM_CLIENT_SECRET,AIM_ORG_ID) ~/.aim/sdk_credentials.json./.aim/credentials.json(project-local)./sdk_credentials.json(current directory)
Programmatic access:
import org.opena2a.aim.credentials.CredentialManager;
Map<String, String> creds = CredentialManager.loadSdkCredentials();
Map<String, String> agentCreds = CredentialManager.loadAgentCredentials("my-agent");Credential files are written with mode 0600. Agent private keys are returned once at registration; the SDK saves them to ~/.aim/agents/<id>.json.
The version of each library is pinned in pom.xml.
| Library | Purpose |
|---|---|
| OkHttp | HTTP client |
| Jackson | JSON processing |
| BouncyCastle | Ed25519 cryptography |
| AspectJ | AOP for @SecureAction |
| SLF4J | Logging |
- Java 17 or higher
- Maven 3.6+ to build the SDK
Semantic Versioning 2.0.0. Current: 1.0.0. SDK 1.x.x is compatible with backend 1.x.x.
- Python SDK — same API shape, decorator-based
- TypeScript SDK — local-or-server mode
- opena2a CLI — codebase auditing, credential migration, runtime monitoring
- AIM backend — server, dashboard, deployment
Apache-2.0. See LICENSE.