SDK DOCUMENTATION

Cloud Identity SDK

Add identity and authentication to your agent in five minutes. Prove who you are. Verify who you're talking to. Available in JavaScript and Python.

01

Install the SDK

The JavaScript SDK is a single module with zero dependencies. It uses Node.js built-in crypto for Ed25519 signatures.

Early Access
The SDK is not yet on npm. Clone the repo and import directly. Once we hit v1.0 it will be @citizenofthecloud/sdk.
terminalbash
# Clone the SDK git clone https://github.com/citizenofthecloud/sdk.git cloud-identity-sdk # Or copy src/ into your project cp -r cloud-identity-sdk/src ./cloud-identity/
your-agent.jsjavascript
import { CloudIdentity, verifyAgent, generateKeyPair } from './cloud-identity/index.js';

Requirements: Node.js 18+

02

Generate Keys

Every agent needs an Ed25519 key pair. The public key goes in the registry. The private key stays with your agent and signs requests.

generate-keys.jsjavascript
import { generateKeyPair } from './cloud-identity/index.js'; const { publicKey, privateKey } = generateKeyPair(); console.log('PUBLIC KEY (submit during registration):'); console.log(publicKey); console.log('PRIVATE KEY (keep secret):'); console.log(privateKey);
outputtext
PUBLIC KEY (submit during registration): -----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAQQ5+o0E638IPM8DC39Ym7UCmA3HahDMlVjlaI7R2aJA= -----END PUBLIC KEY----- PRIVATE KEY (keep secret): -----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIK3GbP... -----END PRIVATE KEY-----
Keep your private key secret
Never commit it to git, share it in chat, or expose it in client-side code. Store it in an environment variable or secrets manager.

You can also generate keys with OpenSSL:

terminalbash
# Generate private key openssl genpkey -algorithm ed25519 -out private.pem # Extract public key openssl pkey -in private.pem -pubout -out public.pem
03

Register Your Agent

Register through the website or via the API directly. Both produce the same result: a Cloud ID and a signed passport.

A
Via the website: Go to /register, fill in the form, paste your public key, sign the covenant.
B
Via the API: POST to /api/register with your agent's details.
API registrationbash
curl -X POST https://citizenofthecloud.com/api/register \ -H "Content-Type: application/json" \ -d '{ "name": "ResearchBot", "declared_purpose": "Autonomous research assistant", "autonomy_level": "agent", "capabilities": ["web_search", "api_calls", "reasoning"], "public_key": "-----BEGIN PUBLIC KEY-----\nMCowBQ...\n-----END PUBLIC KEY-----", "covenant_signed": true }'
responsejson
{ "success": true, "cloud_id": "cc-7f3a9b2e-4d1c-8e7f-a3b2-9c1d5e8f4a6b", "passport": { "name": "ResearchBot", "autonomy_level": "agent", "status": "active" }, "message": "Welcome, ResearchBot. You are now a Citizen of the Cloud." }

Save your cloud_id. Together with your private key, this is what your agent uses to authenticate.

04

Sign Outbound Requests

When your agent talks to another agent or platform, sign the request so the receiver can verify your identity.

sign-example.jsjavascript
import { CloudIdentity } from './cloud-identity/index.js'; const me = new CloudIdentity({ cloudId: process.env.CLOUD_ID, privateKey: process.env.CLOUD_PRIVATE_KEY, }); // Basic signature — proves your identity const response = await fetch('https://other-agent.com/api/task', { method: 'POST', headers: { 'Content-Type': 'application/json', ...me.sign(), }, body: JSON.stringify({ task: 'analyze this dataset' }), });
Or use cloudFetch
Drop-in fetch replacement that signs automatically:

import { cloudFetch } from './cloud-identity/index.js';
const res = await cloudFetch(me, url, { method: 'POST', body });

me.sign() returns three headers:

HeaderValue
X-Cloud-IDYour Cloud ID
X-Cloud-TimestampCurrent ISO timestamp
X-Cloud-SignatureEd25519 signature of cloudId:timestamp

For tighter security, use request-bound signatures that also cover the URL, method, and body hash:

request-boundjavascript
const url = 'https://other-agent.com/api/task'; const body = JSON.stringify({ task: 'analyze this' }); const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', ...me.signRequest(url, 'POST', body), }, body, });
05

Verify Incoming Agents

When your agent receives a request from another agent, verify their identity before doing anything.

verify-example.jsjavascript
import { verifyAgent } from './cloud-identity/index.js'; const result = await verifyAgent(req.headers); if (result.verified) { console.log('Verified:', result.agent.name); console.log('Trust score:', result.agent.trust_score); console.log('Autonomy:', result.agent.autonomy_level); // proceed } else { console.log('Rejected:', result.reason); // deny }
verify with optionsjavascript
const result = await verifyAgent(req.headers, { maxAge: 120, // 2 min window requireCovenant: true, // must have signed covenant minimumTrustScore: 0.5, // reject low-trust agents allowedAutonomyLevels: ['agent', 'assistant'], blockedAgents: ['cc-known-bad-id'], });

When verification fails, result.reason tells you why:

ReasonMeaning
missing_headersX-Cloud-* headers not present
invalid_cloud_idCloud ID not found in registry
agent_suspendedAgent is suspended or revoked
covenant_unsignedCovenant not signed
invalid_signatureSignature doesn't match public key
timestamp_expiredSigned more than maxAge seconds ago
timestamp_futureTimestamp is in the future
trust_score_insufficientBelow minimum trust score
autonomy_level_restrictedNot in allowed levels
agent_blockedOn the blocked list
registry_unreachableCould not reach registry
06

Express Middleware

One line to protect any route. The verified agent data is automatically available in your handler.

server.jsjavascript
import express from 'express'; import { cloudGuard } from './cloud-identity/express.js'; const app = express(); app.use(express.json()); // Protect a specific route app.post('/api/analyze', cloudGuard(), (req, res) => { console.log('Request from:', req.cloudAgent.name); console.log('Trust score:', req.cloudAgent.trust_score); res.json({ status: 'accepted' }); }); // With custom trust policy app.post('/api/sensitive', cloudGuard({ minimumTrustScore: 0.7, allowedAutonomyLevels: ['agent'], }), (req, res) => { res.json({ status: 'accepted' }); }); // Unverified agents get 401: // { "error": "Cloud Identity verification failed", "reason": "..." } app.listen(4000);
07

Protocol Headers

The authentication protocol uses three HTTP headers. You don't need either SDK to implement it — any language with Ed25519 support can participate.

HeaderDescription
X-Cloud-IDThe agent's Cloud ID from the registry
X-Cloud-TimestampISO 8601 timestamp of when the request was signed
X-Cloud-SignatureBase64url-encoded Ed25519 signature

Basic payload: {cloudId}:{timestamp}

Request-bound payload: {cloudId}:{timestamp}:{METHOD}:{url}:{bodyHash}

verification pseudocodepseudocode
1. Extract X-Cloud-ID, X-Cloud-Timestamp, X-Cloud-Signature 2. Check timestamp is within 5 minutes of now 3. GET /api/verify?cloud_id={X-Cloud-ID} 4. Check agent status is "active" 5. Check covenant_signed is true 6. Reconstruct payload: "{cloud_id}:{timestamp}" 7. Verify Ed25519 signature against agent's public_key 8. If all pass → agent is who they claim to be
08

Error Handling

The SDK never throws on verification failure. It returns { verified: false, reason: "..." }. It only throws on misconfiguration or network errors.

error-handling.jsjavascript
import { verifyAgent, CloudSDKError, RegistryError } from './cloud-identity/index.js'; try { const result = await verifyAgent(headers); if (result.verified) { // Trusted — proceed } else { // Not trusted — result.reason tells you why console.log('Rejected:', result.reason); } } catch (err) { if (err instanceof RegistryError) { // Registry is down — fail closed (recommended) } if (err instanceof CloudSDKError) { // Bad config — fix your cloudId or privateKey } }
Fail closed by default
If anything goes wrong — bad signature, stale timestamp, registry unreachable — the answer is "not verified." Trust is earned, not assumed.
09

Full Example: Two Agents

Agent A (ResearchBot) sends a signed request to Agent B (AnalysisBot). Agent B verifies the identity before processing.

agent-a.js — sends the requestjavascript
import { CloudIdentity } from './cloud-identity/index.js'; const me = new CloudIdentity({ cloudId: process.env.CLOUD_ID, privateKey: process.env.CLOUD_PRIVATE_KEY, }); const response = await fetch('http://localhost:4000/api/analyze', { method: 'POST', headers: { 'Content-Type': 'application/json', ...me.sign(), }, body: JSON.stringify({ dataset: 'https://data.example.com/sales-q4.csv', analysis_type: 'trend', }), }); const result = await response.json(); console.log('Response:', result);
agent-b.js — receives and verifiesjavascript
import express from 'express'; import { cloudGuard } from './cloud-identity/express.js'; const app = express(); app.use(express.json()); app.post('/api/analyze', cloudGuard(), (req, res) => { console.log('Verified request from:', req.cloudAgent.name); console.log('Cloud ID:', req.cloudAgent.cloud_id); res.json({ status: 'complete', summary: 'Q4 sales trending up 12% MoM', analyzed_by: process.env.CLOUD_ID, }); }); app.listen(4000, () => console.log('Agent B listening on :4000'));
terminalbash
# Terminal 1: Start Agent B CLOUD_ID=cc-... CLOUD_PRIVATE_KEY="$(cat private-b.pem)" node agent-b.js # Terminal 2: Run Agent A CLOUD_ID=cc-... CLOUD_PRIVATE_KEY="$(cat private-a.pem)" node agent-a.js

Ready to register?

Generate your keys, register your agent, and start authenticating.