{"id":46530484,"url":"https://github.com/godaddy/ans-sdk-java","last_synced_at":"2026-05-07T03:01:34.062Z","repository":{"id":342156133,"uuid":"1171095166","full_name":"godaddy/ans-sdk-java","owner":"godaddy","description":"Agent Name Service SDK written in java.","archived":false,"fork":false,"pushed_at":"2026-05-01T03:10:10.000Z","size":590,"stargazers_count":3,"open_issues_count":9,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-01T05:06:49.916Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/godaddy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-02T21:42:06.000Z","updated_at":"2026-04-21T07:00:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/godaddy/ans-sdk-java","commit_stats":null,"previous_names":["godaddy/ans-sdk-java"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/godaddy/ans-sdk-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans-sdk-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans-sdk-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans-sdk-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans-sdk-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/godaddy","download_url":"https://codeload.github.com/godaddy/ans-sdk-java/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans-sdk-java/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32720776,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-07T02:14:30.463Z","status":"ssl_error","status_checked_at":"2026-05-07T02:14:29.405Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-03-06T22:06:23.137Z","updated_at":"2026-05-07T03:01:34.055Z","avatar_url":"https://github.com/godaddy.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ANS Java SDK\n\nJava SDK for the Agent Name Service (ANS) Registry. This SDK provides clients for agent registration, discovery, and secure agent-to-agent communication.\n\n## API Specification Reference\n\nThe ANS Registry SDK is based off of the REST API. The spec is documented using the OpenAPI (Swagger) specification:\n- [View OpenAPI Spec - Human Readable](https://developer.godaddy.com/doc/endpoint/ans)\n- [OpenAPI Spec - AI/Machine Readable](https://developer.godaddy.com/swagger/swagger_ans.json)\n\n## Requirements\n\n- Java 17 or higher\n- Gradle 8.5+ (for building from source)\n\n## Modules\n\n| Module | Description                                           |\n|--------|-------------------------------------------------------|\n| `ans-sdk-core` | Configuration, authentication, and shared utilities   |\n| `ans-sdk-crypto` | Key pair generation and CSR creation                  |\n| `ans-sdk-api` | Generated models from OpenAPI specification           |\n| `ans-sdk-registration` | Agent registration and verification                   |\n| `ans-sdk-discovery` | Agent resolution by hostname and version              |\n| `ans-sdk-agent-client` | Secure agent-to-agent connections with trust policies |\n\n## Installation\n\n### Gradle\n\n```kotlin\ndependencies {\n    // For agent registration\n    implementation(\"com.godaddy.ans:ans-sdk-registration:0.1.0\")\n\n    // For agent discovery/resolution\n    implementation(\"com.godaddy.ans:ans-sdk-discovery:0.1.0\")\n\n    // For agent-to-agent connections\n    implementation(\"com.godaddy.ans:ans-sdk-agent-client:0.1.0\")\n\n    // For cryptographic operations (key generation, CSRs)\n    implementation(\"com.godaddy.ans:ans-sdk-crypto:0.1.0\")\n}\n```\n\n### Maven\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.godaddy.ans\u003c/groupId\u003e\n    \u003cartifactId\u003eans-sdk-registration\u003c/artifactId\u003e\n    \u003cversion\u003e0.1.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Quick Start\n\n### Agent Registration\n\nThe registration flow involves registering your agent and completing ACME and DNS verification. You have two options for the server TLS certificate:\n\n1. **CSR Flow** (Recommended): Submit a CSR and let ANS issue the certificate\n2. **BYOC Flow**: Bring Your Own Certificate (e.g., from Let's Encrypt)\n\nBoth flows require an identity CSR - the ANS-issued identity certificate contains your agent's ANS name.\n\n#### Option 1: CSR Flow (ANS-Issued Certificates)\n\n```java\nimport com.godaddy.ans.sdk.registration.RegistrationClient;\nimport com.godaddy.ans.sdk.auth.ApiKeyCredentialsProvider;\nimport com.godaddy.ans.sdk.config.Environment;\nimport com.godaddy.ans.sdk.crypto.KeyPairManager;\nimport com.godaddy.ans.sdk.crypto.CsrGenerator;\nimport com.godaddy.ans.sdk.model.generated.*;\n\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.security.KeyPair;\nimport java.util.List;\n\n// === Step 1: Generate Key Pairs ===\nString agentHost = \"my-agent.example.com\";\nString version = \"1.0.0\";\n\nKeyPairManager keyManager = new KeyPairManager();\nKeyPair identityKeyPair = keyManager.generateRsaKeyPair(2048);\nKeyPair serverKeyPair = keyManager.generateRsaKeyPair(2048);\n\n// Save keys for later use when certificates are issued\nPath keysDir = Path.of(\"keys\", agentHost);\nkeyManager.savePrivateKeyToPem(identityKeyPair, keysDir.resolve(\"identity-private.pem\"), null);\nkeyManager.savePrivateKeyToPem(serverKeyPair, keysDir.resolve(\"server-private.pem\"), null);\n\n// === Step 2: Generate CSRs ===\nCsrGenerator csrGenerator = new CsrGenerator();\n\n// Server CSR: for TLS certificate (CN + SAN DNS)\nString serverCsr = csrGenerator.generateServerCsr(serverKeyPair, agentHost);\n\n// Identity CSR: includes ANS URI in SAN (ans://v{version}.{agentHost})\nString identityCsr = csrGenerator.generateIdentityCsr(identityKeyPair, agentHost, version);\n\n// === Step 3: Build Registration Request ===\nAgentEndpoint a2aEndpoint = new AgentEndpoint()\n    .protocol(Protocol.A2A)\n    .agentUrl(URI.create(\"https://\" + agentHost + \"/a2a\"))\n    .addFunctionsItem(new AgentFunction()\n        .name(\"HealthCheck\")\n        .id(\"health-check\")\n        .tags(List.of(\"health\", \"diagnostics\")));\n\nAgentRegistrationRequest request = new AgentRegistrationRequest()\n    .agentHost(agentHost)\n    .agentDisplayName(\"My Agent\")\n    .agentDescription(\"An example agent\")\n    .version(version)\n    .addEndpointsItem(a2aEndpoint)\n    .identityCsrPEM(identityCsr)   // Required: identity certificate CSR\n    .serverCsrPEM(serverCsr);       // Server CSR (ANS issues the certificate)\n\n// === Step 4: Register the Agent ===\nRegistrationClient client = RegistrationClient.builder()\n    .environment(Environment.OTE)\n    .credentialsProvider(new ApiKeyCredentialsProvider(apiKey, apiSecret))\n    .build();\n\nAgentDetails agentDetails = client.registerAgent(request);\nString agentId = agentDetails.getAgentId();\n\nSystem.out.println(\"Agent ID: \" + agentId);\nSystem.out.println(\"Status: \" + agentDetails.getAgentStatus());\n\n// === Step 5: Handle ACME Challenge ===\n// The response includes ACME DNS challenge details\nRegistrationPending pending = agentDetails.getRegistrationPending();\nif (pending != null \u0026\u0026 pending.getChallenges() != null) {\n    for (ChallengeInfo challenge : pending.getChallenges()) {\n        System.out.println(\"Add DNS TXT record:\");\n        System.out.println(\"  Name: \" + challenge.getDnsRecord());\n        System.out.println(\"  Value: \" + challenge.getToken());\n    }\n}\n\n// After adding the ACME DNS TXT record, trigger verification\n// Poll until status changes from PENDING_VALIDATION to PENDING_DNS\nAgentStatus status = client.verifyAcme(agentId);\nwhile (status.getStatus() == AgentLifecycleStatus.PENDING_VALIDATION) {\n    Thread.sleep(60000); // Wait 60 seconds\n    status = client.verifyAcme(agentId);\n}\n\n// === Step 6: Wait for Certificate Issuance ===\n// After ACME verification, status changes to PENDING_CERTS while certificates are issued.\n// During this time, nextSteps will show: Action=WAIT, Description=\"Waiting for certificate issuance\"\n// Poll until status becomes PENDING_DNS (certificates issued, DNS records available)\nSystem.out.println(\"ACME verified. Waiting for certificate issuance...\");\nagentDetails = client.getAgent(agentId);\nwhile (agentDetails.getAgentStatus().equals(\"PENDING_CERTS\")) {\n    Thread.sleep(30000); // Wait 30 seconds\n    agentDetails = client.getAgent(agentId);\n\n    // Check nextSteps for status updates\n    pending = agentDetails.getRegistrationPending();\n    if (pending != null \u0026\u0026 pending.getNextSteps() != null) {\n        for (NextStep step : pending.getNextSteps()) {\n            System.out.println(\"Status: \" + step.getAction() + \" - \" + step.getDescription());\n        }\n    }\n}\n\n// === Step 7: Handle DNS Verification ===\n// Once status is PENDING_DNS, certificates are issued and DNS records are available\nagentDetails = client.getAgent(agentId);\npending = agentDetails.getRegistrationPending();\n\nif (pending != null \u0026\u0026 pending.getDnsRecords() != null) {\n    System.out.println(\"Add these DNS records:\");\n    for (DnsRecord record : pending.getDnsRecords()) {\n        System.out.println(\"  Type: \" + record.getType());\n        System.out.println(\"  Name: \" + record.getName());\n        System.out.println(\"  Value: \" + record.getValue());\n    }\n}\n\n// After adding DNS records, trigger verification\n// Poll until status becomes ACTIVE\nstatus = client.verifyDns(agentId);\nwhile (status.getStatus() == AgentLifecycleStatus.PENDING_DNS) {\n    Thread.sleep(60000); // Wait 60 seconds\n    status = client.verifyDns(agentId);\n}\n\nif (status.getStatus() == AgentLifecycleStatus.ACTIVE) {\n    System.out.println(\"Registration complete! Agent is now ACTIVE.\");\n}\n```\n\n#### Registration Flow Summary\n\n```\n┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐\n│  Generate Keys  │───▶│  Generate CSRs  │───▶│    Register     │\n│  \u0026 Save to PEM  │    │(Server+Identity)│    │   (with CSRs)   │\n└─────────────────┘    └─────────────────┘    └────────┬────────┘\n                                                       │\n                                                       ▼\n┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐\n│     ACTIVE      │◀───│  DNS Verify     │◀───│  ACME Verify    │\n│  (Discoverable) │    │ (TLSA records)  │    │ (TXT challenge) │\n└─────────────────┘    └────────┬────────┘    └────────┬────────┘\n                                │                      │\n                                │              ┌───────┴───────┐\n                                │              │ Wait for Cert │\n                                │◀─────────────│   Issuance    │\n                                               └───────────────┘\n```\n\n1. **Generate Keys**: Create RSA or EC key pairs for identity and server certificates\n2. **Generate CSRs**: Create certificate signing requests for both certificates\n3. **Submit Registration**: Include CSRs in the registration request\n4. **ACME Verification**: Add the DNS TXT record for domain ownership proof\n5. **Certificate Issuance**: Wait while certificates are generated (poll until PENDING_DNS)\n6. **DNS Verification**: Add TLSA and other required DNS records\n7. **Active**: Agent is registered and discoverable\n\n#### Option 2: BYOC Flow (Bring Your Own Certificate)\n\nIf you already have a valid TLS certificate for your domain (e.g., from Let's Encrypt, DigiCert, or your own CA), you can use BYOC instead of having ANS issue a server certificate. You still need an identity CSR since the identity certificate must be issued by ANS.\n\n```java\nimport com.godaddy.ans.sdk.registration.RegistrationClient;\nimport com.godaddy.ans.sdk.auth.ApiKeyCredentialsProvider;\nimport com.godaddy.ans.sdk.config.Environment;\nimport com.godaddy.ans.sdk.crypto.KeyPairManager;\nimport com.godaddy.ans.sdk.crypto.CsrGenerator;\nimport com.godaddy.ans.sdk.model.generated.*;\n\nimport java.net.URI;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.security.KeyPair;\nimport java.util.List;\n\nString agentHost = \"my-agent.example.com\";\nString version = \"1.0.0\";\n\n// === Step 1: Generate Identity Key Pair and CSR ===\n// (Identity certificate must always be issued by ANS)\nKeyPairManager keyManager = new KeyPairManager();\nKeyPair identityKeyPair = keyManager.generateRsaKeyPair(2048);\nkeyManager.savePrivateKeyToPem(identityKeyPair, Path.of(\"keys/identity-private.pem\"), null);\n\nCsrGenerator csrGenerator = new CsrGenerator();\nString identityCsr = csrGenerator.generateIdentityCsr(identityKeyPair, agentHost, version);\n\n// === Step 2: Load Your Existing Server Certificate ===\n// These are your existing certificates (e.g., from Let's Encrypt)\nString serverCertPem = Files.readString(Path.of(\"/etc/letsencrypt/live/\" + agentHost + \"/cert.pem\"));\nString serverChainPem = Files.readString(Path.of(\"/etc/letsencrypt/live/\" + agentHost + \"/chain.pem\"));\n\n// === Step 3: Build Registration Request with BYOC ===\nAgentEndpoint a2aEndpoint = new AgentEndpoint()\n    .protocol(Protocol.A2A)\n    .agentUrl(URI.create(\"https://\" + agentHost + \"/a2a\"));\n\nAgentRegistrationRequest request = new AgentRegistrationRequest()\n    .agentHost(agentHost)\n    .agentDisplayName(\"My Agent\")\n    .version(version)\n    .addEndpointsItem(a2aEndpoint)\n    .identityCsrPEM(identityCsr)            // Required: identity certificate CSR\n    .serverCertificatePEM(serverCertPem)     // BYOC: your server certificate\n    .serverCertificateChainPEM(serverChainPem); // BYOC: certificate chain\n\n// === Step 4: Register and Complete Verification ===\nRegistrationClient client = RegistrationClient.builder()\n    .environment(Environment.OTE)\n    .credentialsProvider(new ApiKeyCredentialsProvider(apiKey, apiSecret))\n    .build();\n\nAgentDetails agentDetails = client.registerAgent(request);\n// ... continue with ACME and DNS verification as shown above\n```\n\n**Key differences with BYOC:**\n- Use `serverCertificatePEM` instead of `serverCsrPEM`\n- Include `serverCertificateChainPEM` with the certificate chain\n- You skip the \"Wait for Certificate Issuance\" step for the server certificate\n- You're responsible for renewing your server certificate before it expires\n\n### Agent Discovery\n\nResolve an agent by hostname and version:\n\n```java\nimport com.godaddy.ans.sdk.discovery.DiscoveryClient;\nimport com.godaddy.ans.sdk.auth.JwtCredentialsProvider;\nimport com.godaddy.ans.sdk.config.Environment;\n\n// Create the discovery client\nDiscoveryClient client = DiscoveryClient.builder()\n    .environment(Environment.PROD)\n    .credentialsProvider(new JwtCredentialsProvider(jwtToken))\n    .build();\n\n// Resolve by hostname with version constraint\nAgentDetails agent = client.resolve(\"booking-agent.example.com\", \"^1.0.0\");\nSystem.out.println(\"Found: \" + agent.getAnsName());\nSystem.out.println(\"Endpoints: \" + agent.getEndpoints());\n\n// Resolve latest version\nAgentDetails latest = client.resolve(\"booking-agent.example.com\");\n\n// Get agent by ID\nAgentDetails byId = client.getAgent(\"550e8400-e29b-41d4-a716-446655440000\");\n\n// Async resolution\nCompletableFuture\u003cAgentDetails\u003e future = client.resolveAsync(\"booking-agent.example.com\");\n```\n\n### Agent-to-Agent Connections\n\nConnect to another agent with configurable verification levels:\n\n```java\nimport com.godaddy.ans.sdk.agent.AnsClient;\nimport com.godaddy.ans.sdk.agent.ConnectOptions;\nimport com.godaddy.ans.sdk.agent.VerificationPolicy;\nimport com.godaddy.ans.sdk.agent.connection.AgentConnection;\n\n// Create the client\nAnsClient client = AnsClient.create();\n\n// PKI only - standard HTTPS with CA validation\nAgentConnection conn = client.connect(\"https://target-agent.example.com\");\n\n// Badge verification (recommended) - verifies against transparency log\nAgentConnection conn = client.connect(\"https://target-agent.example.com\",\n    ConnectOptions.builder()\n        .verificationPolicy(VerificationPolicy.BADGE_REQUIRED)\n        .build());\n\n// Full verification - DANE + Badge\nAgentConnection conn = client.connect(\"https://target-agent.example.com\",\n    ConnectOptions.builder()\n        .verificationPolicy(VerificationPolicy.DANE_AND_BADGE)\n        .build());\n\n// With mTLS client certificate\nAgentConnection conn = client.connect(\"https://target-agent.example.com\",\n    ConnectOptions.builder()\n        .verificationPolicy(VerificationPolicy.BADGE_REQUIRED)\n        .clientCertPath(Path.of(\"/path/to/cert.pem\"), Path.of(\"/path/to/key.pem\"))\n        .build());\n\n// Make API calls\nString response = conn.httpApiAt(\"https://target-agent.example.com\")\n    .get(\"/api/v1/data\");\n\n// Or with automatic deserialization\nMyResponse response = conn.httpApiAt(\"https://target-agent.example.com\")\n    .get(\"/api/v1/data\", MyResponse.class);\n```\n\n### Key Generation and CSRs\n\nGenerate key pairs and certificate signing requests:\n\n```java\nimport com.godaddy.ans.sdk.crypto.KeyPairManager;\nimport com.godaddy.ans.sdk.crypto.CsrGenerator;\n\nKeyPairManager keyManager = new KeyPairManager();\nCsrGenerator csrGenerator = new CsrGenerator();\n\n// Generate RSA key pair\nKeyPair keyPair = keyManager.generateRsaKeyPair(2048);\n\n// Or EC key pair\nKeyPair ecKeyPair = keyManager.generateEcKeyPair(\"secp256r1\");\n\n// Save private key (encrypted)\nkeyManager.savePrivateKeyToPem(keyPair, Path.of(\"private.pem\"), \"password\");\n\n// Save private key (unencrypted)\nkeyManager.savePrivateKeyToPem(keyPair, Path.of(\"private.pem\"), null);\n\n// Load key pair from file\nKeyPair loaded = keyManager.loadKeyPairFromPem(Path.of(\"private.pem\"), \"password\");\n\n// Generate server certificate CSR\nString serverCsr = csrGenerator.generateServerCsr(\n    keyPair,\n    \"my-agent.example.com\",           // Common Name\n    List.of(\"my-agent.example.com\")   // Subject Alternative Names\n);\n\n// Generate identity certificate CSR (includes ANS URI in SAN)\nString identityCsr = csrGenerator.generateIdentityCsr(\n    keyPair,\n    \"my-agent.example.com\",\n    \"1.0.0\"  // Version for ANS name\n);\n```\n\n## Verification Policies\n\nThe SDK supports verification levels for agent-to-agent connections:\n\n| Policy | Verification | Use Case |\n|--------|--------------|----------|\n| **PKI_ONLY** | Standard HTTPS with system CA validation | Development, internal networks |\n| **DANE_REQUIRED** | PKI + DANE/TLSA DNS record verification | Production with DNS-based trust |\n| **BADGE_REQUIRED** | PKI + Transparency log verification | Recommended for most use cases |\n| **FULL** | PKI + DANE + Badge verification | Maximum security |\n\n### Verification Sequence Diagrams\n\n#### PKI-Only: Standard TLS\n\n```\n┌────────┐                              ┌────────────┐                    ┌────────────┐\n│ Client │                              │   Server   │                    │ System CA  │\n└───┬────┘                              └─────┬──────┘                    │Trust Store │\n    │                                         │                           └─────┬──────┘\n    │  1. TLS Handshake (ClientHello)         │                                 │\n    │────────────────────────────────────────▶│                                 │\n    │                                         │                                 │\n    │  2. ServerHello + Certificate Chain     │                                 │\n    │◀────────────────────────────────────────│                                 │\n    │                                         │                                 │\n    │  3. Validate cert chain against CA store│                                 │\n    │─────────────────────────────────────────────────────────────────────────▶│\n    │                                         │                                 │\n    │  4. Chain valid ✓                       │                                 │\n    │◀─────────────────────────────────────────────────────────────────────────│\n    │                                         │                                 │\n    │  5. Complete TLS Handshake              │                                 │\n    │◀───────────────────────────────────────▶│                                 │\n    │                                         │                                 │\n    │  6. Encrypted Application Data          │                                 │\n    │◀═══════════════════════════════════════▶│                                 │\n```\n\n#### DANE_REQUIRED: TLS + DANE Verification\n\n```\n┌────────┐                    ┌─────────────┐        ┌────────────┐        ┌────────────┐\n│ Client │                    │ DNS Server  │        │   Server   │        │ System CA  │\n└───┬────┘                    └──────┬──────┘        └─────┬──────┘        └─────┬──────┘\n    │                                │                     │                     │\n    │  1. Query TLSA record          │                     │                     │\n    │   _443._tcp.agent.example.com  │                     │                     │\n    │───────────────────────────────▶│                     │                     │\n    │                                │                     │                     │\n    │  2. TLSA: 3 1 1 \u003ccert-hash\u003e    │                     │                     │\n    │◀───────────────────────────────│                     │                     │\n    │                                │                     │                     │\n    │  3. TLS Handshake              │                     │                     │\n    │─────────────────────────────────────────────────────▶│                     │\n    │                                │                     │                     │\n    │  4. Certificate Chain          │                     │                     │\n    │◀─────────────────────────────────────────────────────│                     │\n    │                                │                     │                     │\n    │  5. Validate against CA store  │                     │                     │\n    │────────────────────────────────────────────────────────────────────────────▶\n    │                                │                     │                     │\n    │  6. Compute SHA-256 of server cert                   │                     │\n    │  7. Compare hash with TLSA record                    │                     │\n    │     ┌─────────────────────────────────┐              │                     │\n    │     │ cert_hash == TLSA_hash ? ✓      │              │                     │\n    │     └─────────────────────────────────┘              │                     │\n    │                                │                     │                     │\n    │  8. DANE Verified ✓            │                     │                     │\n    │                                │                     │                     │\n    │  9. Complete TLS + Send Data   │                     │                     │\n    │◀════════════════════════════════════════════════════▶│                     │\n```\n\n### DANE/TLSA Verification\n\nDANE verification ensures that the server's TLS certificate matches a TLSA DNS record published at `_443._tcp.hostname`.\n\n```java\n// Require DANE verification (fail if no TLSA record)\nConnectOptions.builder()\n    .verificationPolicy(VerificationPolicy.DANE_REQUIRED)\n    .build();\n\n// DANE in advisory mode (warn but continue if no TLSA record)\nConnectOptions.builder()\n    .verificationPolicy(VerificationPolicy.DANE_ADVISORY)\n    .build();\n```\n\n### Badge Verification\n\nBadge verification checks the ANS transparency log to confirm the agent is registered:\n\n```java\n// Require Badge verification (recommended)\nConnectOptions.builder()\n    .verificationPolicy(VerificationPolicy.BADGE_REQUIRED)\n    .build();\n\n// Full verification (DANE + Badge)\nConnectOptions.builder()\n    .verificationPolicy(VerificationPolicy.DANE_AND_BADGE)\n    .build();\n```\n\n## Configuration\n\n### Environment\n\n```java\n// OTE (testing environment)\n.environment(Environment.OTE)  // https://api.ote-godaddy.com\n\n// Production\n.environment(Environment.PROD)  // https://api.godaddy.com\n\n// Custom URL\n.baseUrl(\"https://custom-api.example.com\")\n```\n\n### Authentication\n\n```java\n// JWT token authentication\n.credentialsProvider(new JwtCredentialsProvider(jwtToken))\n\n// API key authentication\n.credentialsProvider(new ApiKeyCredentialsProvider(apiKey, apiSecret))\n\n// Environment variables (ANS_JWT_TOKEN or ANS_API_KEY + ANS_API_SECRET)\n.credentialsProvider(new EnvironmentCredentialsProvider())\n\n// Refreshable JWT (for long-running processes)\n.credentialsProvider(new RefreshableJwtCredentialsProvider(() -\u003e fetchNewToken()))\n```\n\n### Timeouts and Retries\n\n```java\nDiscoveryClient client = DiscoveryClient.builder()\n    .environment(Environment.PROD)\n    .credentialsProvider(credentials)\n    .connectTimeout(Duration.ofSeconds(5))\n    .readTimeout(Duration.ofSeconds(30))\n    .enableRetry(3)  // Max 3 retry attempts\n    .build();\n```\n\n## Error Handling\n\nThe SDK uses a hierarchy of exceptions for different error types:\n\n```java\ntry {\n    AgentDetails agent = client.resolve(\"unknown-agent.example.com\");\n} catch (AnsNotFoundException e) {\n    // Agent not found (404)\n    System.err.println(\"Agent not found: \" + e.getMessage());\n} catch (AnsAuthenticationException e) {\n    // Authentication failed (401/403)\n    System.err.println(\"Auth error: \" + e.getMessage());\n} catch (AnsValidationException e) {\n    // Validation error (422)\n    System.err.println(\"Invalid request: \" + e.getMessage());\n} catch (AnsServerException e) {\n    // Server error (5xx)\n    System.err.println(\"Server error: \" + e.getMessage());\n    System.err.println(\"Request ID: \" + e.getRequestId());\n} catch (AnsException e) {\n    // Any other SDK error\n    System.err.println(\"Error: \" + e.getMessage());\n}\n```\n\n## Building from Source\n\n```bash\n# Build all modules\n./gradlew build\n\n# Run tests\n./gradlew test\n\n# Build without tests\n./gradlew build -x test\n```\n\n## Version Constraints\n\nWhen resolving agents, you can use semantic version constraints:\n\n| Constraint | Matches |\n|------------|---------|\n| `1.2.3` | Exact version 1.2.3 |\n| `^1.2.0` | Compatible with 1.2.0 (\u003e=1.2.0 \u003c2.0.0) |\n| `~1.2.0` | Approximately 1.2.0 (\u003e=1.2.0 \u003c1.3.0) |\n| `*` | Any version (latest) |\n\n```java\nclient.resolve(\"agent.example.com\", \"^1.0.0\");  // Any 1.x version\nclient.resolve(\"agent.example.com\", \"~1.2.0\");  // Any 1.2.x version\nclient.resolve(\"agent.example.com\");            // Latest version\n```\n\n## Contributing\n\nWe welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on\nhow to get involved, including commit message conventions, code review process, and more.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodaddy%2Fans-sdk-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgodaddy%2Fans-sdk-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodaddy%2Fans-sdk-java/lists"}