Skip to main content
The keystore module provides functions for generating, loading, and using Ed25519 keypairs. These keypairs are used for agent authentication via challenge-response during AgentDoor registration.

Overview

AgentDoor uses Ed25519 public-key cryptography for agent authentication:
  • Keypairs are generated using the tweetnacl library
  • Private keys are stored securely with 0o600 permissions (owner read/write only)
  • Public keys are shared with services during registration
  • Signatures prove the agent owns the private key corresponding to a public key

Functions

generateKeypair()

Generate a fresh Ed25519 keypair.
import { generateKeypair } from "@agentdoor/sdk";

const keypair = generateKeypair();
console.log("Public key:", keypair.publicKeyBase64);
keypair
Keypair
A new keypair object with both raw Uint8Array and base64-encoded representations.

saveKeypair()

Save a keypair to disk as JSON. Creates parent directories if they don’t exist.
import { generateKeypair, saveKeypair } from "@agentdoor/sdk";

const keypair = generateKeypair();
saveKeypair(keypair, "~/.agentdoor/keys.json");
keypair
Keypair
required
The keypair to save.
filePath
string
required
The file path where the keypair will be stored. Supports ~ for home directory expansion. The file will be created with 0o600 permissions (owner read/write only).

loadKeypair()

Load a keypair from disk. Returns null if the file doesn’t exist. Throws if the file exists but is malformed.
import { loadKeypair } from "@agentdoor/sdk";

const keypair = loadKeypair("~/.agentdoor/keys.json");
if (keypair) {
  console.log("Loaded keypair:", keypair.publicKeyBase64);
} else {
  console.log("No keypair found at path");
}
filePath
string
required
The file path to load the keypair from. Supports ~ for home directory expansion.
keypair
Keypair | null
The loaded keypair, or null if the file doesn’t exist.
Throws:
  • Error if the file exists but contains invalid JSON
  • Error if the file is missing required fields (publicKey, secretKey)
  • Error if the key lengths are incorrect (public key must be 32 bytes, secret key must be 64 bytes)

loadOrCreateKeypair()

Load an existing keypair from disk, or generate and save a new one if none exists. This is the recommended way to manage keypairs in most applications.
import { loadOrCreateKeypair } from "@agentdoor/sdk";

const keypair = loadOrCreateKeypair("~/.agentdoor/keys.json");
console.log("Agent public key:", keypair.publicKeyBase64);
filePath
string
The file path for the keypair. Defaults to ~/.agentdoor/keys.json.
keypair
Keypair
The loaded or newly generated keypair.

signMessage()

Sign an arbitrary message with the agent’s secret key. Returns the detached signature as a base64 string.
import { loadOrCreateKeypair, signMessage } from "@agentdoor/sdk";

const keypair = loadOrCreateKeypair();
const message = "agentdoor:challenge:abc123";
const signature = signMessage(message, keypair.secretKey);

console.log("Signature:", signature);
message
string
required
The message to sign. Can be any string.
secretKey
Uint8Array
required
The Ed25519 secret key (64 bytes) to sign with.
signature
string
Base64-encoded detached Ed25519 signature (64 bytes encoded).

verifySignature()

Verify a detached Ed25519 signature against a message and public key.
import { verifySignature, decodeBase64 } from "@agentdoor/sdk";

const message = "agentdoor:challenge:abc123";
const signatureBase64 = "...";
const publicKeyBase64 = "...";

const publicKey = decodeBase64(publicKeyBase64);
const isValid = verifySignature(message, signatureBase64, publicKey);

console.log("Signature valid:", isValid);
message
string
required
The original message that was signed.
signatureBase64
string
required
Base64-encoded signature to verify.
publicKey
Uint8Array
required
The Ed25519 public key (32 bytes) to verify against.
valid
boolean
true if the signature is valid, false otherwise.

Type Definitions

Keypair

In-memory keypair with raw Uint8Arrays alongside base64 representations.
interface Keypair {
  publicKey: Uint8Array;        // 32-byte Ed25519 public key
  secretKey: Uint8Array;        // 64-byte Ed25519 secret key
  publicKeyBase64: string;      // Base64-encoded public key
  secretKeyBase64: string;      // Base64-encoded secret key
}

StoredKeypair

Serialized keypair format stored on disk.
interface StoredKeypair {
  publicKey: string;    // Base64-encoded 32-byte public key
  secretKey: string;    // Base64-encoded 64-byte secret key
  createdAt: string;    // ISO-8601 timestamp
}

Constants

DEFAULT_KEY_PATH

Default keypair file path: ~/.agentdoor/keys.json
import { DEFAULT_KEY_PATH } from "@agentdoor/sdk";

console.log("Default key path:", DEFAULT_KEY_PATH);
// Output: ~/.agentdoor/keys.json

Security Considerations

File Permissions

Keypair files are automatically created with restrictive permissions:
  • Unix/Linux/macOS: 0o600 (owner read/write only)
  • Private keys should never be shared or committed to version control
  • The .agentdoor directory should be added to .gitignore

Key Storage

For production deployments, consider:
  • Using environment variables or secret management systems
  • Encrypting keypair files at rest
  • Rotating keys periodically
  • Using hardware security modules (HSMs) for high-security scenarios

Challenge-Response Flow

During registration, AgentDoor uses challenge-response authentication:
  1. Agent sends its public key to the service
  2. Service generates a random nonce and challenge message
  3. Agent signs the challenge with its private key
  4. Service verifies the signature using the public key
  5. If valid, the service issues credentials
This proves the agent controls the private key without ever transmitting it.

Examples

Generate and Save a Keypair

import { generateKeypair, saveKeypair } from "@agentdoor/sdk";

const keypair = generateKeypair();
saveKeypair(keypair, "~/.agentdoor/keys.json");

console.log("Generated keypair:");
console.log("  Public key:", keypair.publicKeyBase64);
console.log("  Saved to: ~/.agentdoor/keys.json");
import { loadOrCreateKeypair } from "@agentdoor/sdk";

// This will load existing keypair or generate a new one
const keypair = loadOrCreateKeypair("~/.agentdoor/keys.json");

console.log("Agent identity:", keypair.publicKeyBase64);

Sign a Message

import { loadOrCreateKeypair, signMessage } from "@agentdoor/sdk";

const keypair = loadOrCreateKeypair();

// Sign a challenge during registration
const challenge = "agentdoor:challenge:1234567890:abc123";
const signature = signMessage(challenge, keypair.secretKey);

console.log("Challenge:", challenge);
console.log("Signature:", signature);

Verify a Signature

import { 
  generateKeypair, 
  signMessage, 
  verifySignature 
} from "@agentdoor/sdk";

const keypair = generateKeypair();
const message = "Hello, AgentDoor!";

// Sign the message
const signature = signMessage(message, keypair.secretKey);

// Verify the signature
const isValid = verifySignature(message, signature, keypair.publicKey);
console.log("Signature valid:", isValid); // true

// Try verifying with wrong message
const isInvalid = verifySignature("Different message", signature, keypair.publicKey);
console.log("Wrong message valid:", isInvalid); // false

Custom Keypair Location

import { loadOrCreateKeypair } from "@agentdoor/sdk";
import * as path from "path";

// Use a custom location for keypairs
const customPath = path.join(process.cwd(), ".keys", "agent.json");
const keypair = loadOrCreateKeypair(customPath);

console.log("Loaded keypair from:", customPath);

Handle Loading Errors

import { loadKeypair } from "@agentdoor/sdk";

try {
  const keypair = loadKeypair("~/.agentdoor/keys.json");
  
  if (keypair) {
    console.log("Loaded existing keypair");
  } else {
    console.log("No keypair found - need to generate one");
  }
} catch (error) {
  console.error("Failed to load keypair:", error.message);
  // Handle corrupted or invalid keypair file
}

Integration with AgentDoor

The AgentDoor class uses keystore functions internally:
import { AgentDoor } from "@agentdoor/sdk";

// AgentDoor automatically calls loadOrCreateKeypair internally
const agent = new AgentDoor({
  keyPath: "~/.agentdoor/keys.json"
});

// Access the public key
console.log("Agent public key:", agent.publicKey);

// Connect to a service (keypair is used for challenge-response)
const session = await agent.connect("https://api.example.com");

Build docs developers (and LLMs) love