Skip to content

Integration Guide

How to integrate Diogenes into your applications and workflows.


Overview

Diogenes can be integrated in several ways:

  1. REST API -- Direct HTTP calls to the Diogenes server.
  2. Python SDK -- Import Diogenes core modules directly.
  3. Browser signing -- Use the Web Crypto API for client-side signing in web applications.

Python SDK Integration

Diogenes core modules can be imported directly into Python applications.

Key Generation

from diogenes.core.keys import generate_key_pair, compute_fingerprint
from diogenes.core.schemas import KeyAlgorithm

# Generate an Ed25519 key pair
private_key, public_key = generate_key_pair(KeyAlgorithm.ED25519)

# Compute the fingerprint
fingerprint = compute_fingerprint(public_key)
print(f"Fingerprint: {fingerprint}")

Signing a Document

from diogenes.core.signing import create_attestation, verify_attestation_signature
from diogenes.core.schemas import Manifest, Document, Attestation, AttestationType

# Create a manifest
manifest = Manifest(
    document=Document(
        title="My Document",
        content_hash="sha256:abc123...",
    ),
    attestations=[],
)

# Create and sign an attestation
attestation = create_attestation(
    manifest=manifest,
    attestation_type=AttestationType.AUTHORSHIP,
    private_key=private_key,
    fingerprint=fingerprint,
)

# Verify the signature
is_valid = verify_attestation_signature(attestation, public_key)
assert is_valid

Verification

from diogenes.core.verification import VerificationService

service = VerificationService(transparency_log)
result = service.verify(manifest, source_hash)

print(f"Layer 1 (crypto): {result.layer1.status}")
print(f"Layer 2 (key status): {result.layer2.status}")
print(f"Overall: {result.overall_status}")

Transparency Log

from diogenes.core.transparency_log import TransparencyLogService

log = TransparencyLogService()

# Append an entry
entry = log.append_entry(
    event_type="key_registration",
    payload={
        "fingerprint": fingerprint,
        "pseudonym": "Alice",
        "public_key": public_key_pem,
        "key_algorithm": "ed25519",
    },
)

# Verify chain integrity
is_valid = log.verify_chain()

REST API Integration

For applications that communicate with a Diogenes server over HTTP.

Authentication Flow

import httpx

base_url = "http://localhost:8000/api/v1"

# Step 1: Request a login challenge
challenge = httpx.post(f"{base_url}/auth/challenge", json={
    "fingerprint": "sha256:...",
    "purpose": "login",
}).json()

# Step 2: Sign the challenge nonce with your private key
nonce = challenge["nonce"]
signature = sign_with_private_key(nonce.encode())

# Step 3: Login and receive JWT
token_response = httpx.post(f"{base_url}/auth/login", json={
    "challenge_id": challenge["challenge_id"],
    "challenge_signature": base64_encode(signature),
}).json()

jwt = token_response["token"]

# Step 4: Use the JWT for authenticated requests
headers = {"Authorization": f"Bearer {jwt}"}

Webhook Integration

Register a webhook to receive notifications about events:

httpx.post(f"{base_url}/webhooks", json={
    "url": "https://your-app.example.com/hooks/diogenes",
    "events": ["key_registration", "attestation"],
})

Browser-Based Signing

Diogenes supports signing directly in the browser using the Web Crypto API. The private key is generated and used entirely within the browser; it is never transmitted to the server.

Key Generation in JavaScript

// Generate an ECDSA P-256 key pair
const keyPair = await crypto.subtle.generateKey(
  { name: "ECDSA", namedCurve: "P-256" },
  true,  // extractable (for public key export)
  ["sign", "verify"]
);

// Export the public key in SPKI/PEM format
const publicKeyBuffer = await crypto.subtle.exportKey("spki", keyPair.publicKey);
const publicKeyPem = toPem(publicKeyBuffer, "PUBLIC KEY");

Signing in the Browser

// Compute the signing payload
const manifest = { document: { title: "...", content_hash: "..." }, attestations: [] };
const payload = JSON.stringify(manifest, Object.keys(manifest).sort());

// Sign with the private key
const encoder = new TextEncoder();
const signatureBuffer = await crypto.subtle.sign(
  { name: "ECDSA", hash: "SHA-256" },
  keyPair.privateKey,
  encoder.encode(payload)
);

const signature = btoa(String.fromCharCode(...new Uint8Array(signatureBuffer)));

// Submit to the server
const response = await fetch("/api/v1/attestations", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    manifest: manifest,
    public_key_pem: publicKeyPem,
    signature: signature,
    attestation_type: "authorship",
  }),
});

Security Considerations

When integrating Diogenes, keep these principles in mind:

  1. Private keys stay local. Never transmit private keys to the server. All signing happens on the client.
  2. Hash, do not upload. Document content is never sent to the server. Only the SHA-256 hash is transmitted for verification.
  3. Verify server-side. Always verify attestation signatures server-side after receiving them, even though they were created client-side.
  4. Protect passwords. If a key has a password registered, it must be provided with each attestation. Transmit passwords only over TLS.
  5. Rotate keys. Use key succession to rotate keys periodically. Do not reuse keys indefinitely.

Error Handling

All API endpoints return standard HTTP status codes:

Code Meaning
200 Success
201 Created
400 Bad request (invalid input)
401 Authentication required
403 Forbidden (invalid credentials, insufficient permissions)
404 Resource not found
409 Conflict (e.g., challenge already used)
410 Gone (e.g., challenge expired)
422 Validation error (invalid manifest, signature, etc.)
503 Service unavailable (e.g., log unreachable)

Error responses include a detail field with a human-readable message:

{
  "detail": "Signature verification failed: the signature does not match the computed payload for this manifest."
}