Skip to content

Architecture Security

dev-mondoshawan edited this page Apr 16, 2026 · 1 revision

Architecture - Security

**Referenced Files in This Document** - [backend/src/services/bagsAuthVerifier.js](https://github.com/RunTimeAdmin/AgentID/blob/main/backend/src/services/bagsAuthVerifier.js) - [backend/src/services/pkiChallenge.js](https://github.com/RunTimeAdmin/AgentID/blob/main/backend/src/services/pkiChallenge.js) - [backend/src/middleware/rateLimit.js](https://github.com/RunTimeAdmin/AgentID/blob/main/backend/src/middleware/rateLimit.js) - [backend/src/middleware/errorHandler.js](https://github.com/RunTimeAdmin/AgentID/blob/main/backend/src/middleware/errorHandler.js) - [backend/src/models/queries.js](https://github.com/RunTimeAdmin/AgentID/blob/main/backend/src/models/queries.js) - [backend/server.js](https://github.com/RunTimeAdmin/AgentID/blob/main/backend/server.js)

Table of Contents

  1. Introduction
  2. Authentication Architecture
  3. Authorization Architecture
  4. Data Protection
  5. Rate Limiting Architecture
  6. Error Handling Security

Introduction

AgentID's security architecture is built on cryptographic verification using Ed25519 signatures, with defense-in-depth through multiple layers of protection.

Authentication Architecture

Ed25519 Signature Verification

flowchart TD
Start(["Signature Verification"]) --> Decode["Base58 Decode"]
Decode --> Verify["tweetnacl.verify()"]
Verify -->|Valid| Success["Authentication Success"]
Verify -->|Invalid| Failure["Authentication Failure"]

Decode -->|Invalid Format| Failure
Loading

Authentication Flow

sequenceDiagram
participant Client as "Client"
participant Route as "Route Handler"
participant Service as "Auth Service"
participant Crypto as "Crypto Module"
participant DB as "Database"
Client->>Route: Request with signature
Route->>Service: verifySignature()
Service->>Crypto: decode inputs
Crypto-->>Service: decoded bytes
Service->>Crypto: verify Ed25519
Crypto-->>Service: boolean result
Service->>DB: verify nonce not used
DB-->>Service: nonce status
Service-->>Route: auth result
Route-->>Client: response
Loading

PKI Challenge-Response

flowchart TD
Issue["Issue Challenge"] --> GenNonce["Generate UUID"]
GenNonce --> BuildMsg["Build Message:<br/>AGENTID-VERIFY:{pubkey}:{nonce}:{timestamp}"]
BuildMsg --> Store["Store with Expiry"]
Store --> Encode["Base58 Encode"]
Encode --> Return["Return to Client"]

Verify["Verify Response"] --> Load["Load Challenge"]
Load --> CheckExpiry["Check Expiry"]
CheckExpiry --> CheckUsed["Check Not Used"]
CheckUsed --> VerifySig["Verify Signature"]
VerifySig --> MarkUsed["Mark Used"]
MarkUsed --> UpdateTS["Update Timestamp"]
UpdateTS --> ReturnSuccess["Return Success"]

CheckExpiry -->|Expired| Error["Error: Expired"]
CheckUsed -->|Used| Error
VerifySig -->|Invalid| Error
Loading

Authorization Architecture

Permission Model

Action Authorization Method
Read agent data Public
Register agent Ed25519 signature
Update agent Ed25519 signature
Verify challenge Ed25519 signature
Flag agent Ed25519 signature + reporter signature

Signature Requirements

// Registration requires:
{
  pubkey,      // Agent's public key
  signature,   // Ed25519 signature of message
  message,     // Challenge message
  nonce        // Challenge nonce
}

// Flagging requires:
{
  reason,         // Flag reason
  reporterPubkey, // Reporter's public key
  signature,      // Reporter's Ed25519 signature
  timestamp       // Timestamp for freshness
}

Data Protection

SQL Injection Prevention

flowchart LR
Input["User Input"] --> Validate["Input Validation"]
Validate --> ParamQuery["Parameterized Query"]
ParamQuery --> DB[("PostgreSQL")]

Validate -->|Invalid| Reject["Reject Request"]
Loading

All database queries use parameterized statements:

// Safe
await query('SELECT * FROM agents WHERE pubkey = $1', [pubkey]);

// Never do this
await query(`SELECT * FROM agents WHERE pubkey = '${pubkey}'`);

XSS Prevention

Output encoding for dynamic content:

function escapeHtml(text) {
  const map = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };
  return text.replace(/[&<>"']/g, m => map[m]);
}

Rate Limiting Architecture

Rate Limit Tiers

graph TB
Public["Public Endpoints<br/>100 req/15min"] --> Default
Auth["Auth Endpoints<br/>10 req/15min"] --> Strict
Strict["Strict Endpoints<br/>5 req/15min"]
Loading

Implementation

// Default rate limiter
const defaultLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  message: 'Too many requests'
});

// Strict rate limiter for auth
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 10,
  message: 'Too many authentication attempts'
});

// Apply to routes
app.use('/api/', defaultLimiter);
app.use('/api/register', authLimiter);

Error Handling Security

Error Information Disclosure

flowchart TD
Error["Error Occurs"] --> Log["Log Full Error<br/>(Server-side)"]
Log --> CheckEnv{"Environment?"}
CheckEnv -->|Development| DevResponse["Return Detailed Error"]
CheckEnv -->|Production| ProdResponse["Return Generic Error"]
Loading

Security Headers

Helmet.js provides:

Header Purpose
Content-Security-Policy XSS protection
X-Frame-Options Clickjacking protection
X-Content-Type-Options MIME sniffing protection
Strict-Transport-Security HTTPS enforcement
X-DNS-Prefetch-Control DNS prefetch control

Secret Management

flowchart LR
Secrets["Secrets"] --> Env["Environment Variables"]
Env --> App["Application"]

Secrets -->|Production| Vault["Secrets Manager"]
Vault --> App
Loading

Best practices:

  • Never commit secrets to version control
  • Use different keys for different environments
  • Rotate keys regularly
  • Use secrets manager in production

Clone this wiki locally