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.
# 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/
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.
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);
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:
# 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.
AVia the website: Go to
/register, fill in the form, paste your public key, sign the covenant.
BVia the API: POST to /api/register with your agent's details.
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
}'
{
"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.
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:
| Header | Value |
|---|
X-Cloud-ID | Your Cloud ID |
X-Cloud-Timestamp | Current ISO timestamp |
X-Cloud-Signature | Ed25519 signature of cloudId:timestamp |
For tighter security, use request-bound signatures that also cover the URL, method, and body hash:
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.
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
}
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:
| Reason | Meaning |
|---|
missing_headers | X-Cloud-* headers not present |
invalid_cloud_id | Cloud ID not found in registry |
agent_suspended | Agent is suspended or revoked |
covenant_unsigned | Covenant not signed |
invalid_signature | Signature doesn't match public key |
timestamp_expired | Signed more than maxAge seconds ago |
timestamp_future | Timestamp is in the future |
trust_score_insufficient | Below minimum trust score |
autonomy_level_restricted | Not in allowed levels |
agent_blocked | On the blocked list |
registry_unreachable | Could not reach registry |
06
Express Middleware
One line to protect any route. The verified agent data is automatically available in your handler.
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);
08
Error Handling
The SDK never throws on verification failure. It returns { verified: false, reason: "..." }. It only throws on misconfiguration or network errors.
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.
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);
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'));
# 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.