26 KiB
Authentication API Documentation
Authentication Flow and Order of Operations
Authentication Flow Diagram
┌─────────────────────┐
│ Request Received │
└──────────┬──────────┘
│
▼
┌─────────────┐ ╔═══════════════════╗
│ Input Valid?├─No─►║ REJECT: Invalid ║
└──────┬──────┘ ║ Input (~1μs) ║
│Yes ╚═══════════════════╝
▼
┌─────────────┐ ╔═══════════════════╗
│System Init? ├─No─►║ REJECT: Not ║
└──────┬──────┘ ║ Initialized ║
│Yes ╚═══════════════════╝
▼
┌─────────────┐
│Auth Header? │
└──────┬──────┘
│Yes
▼ ┌─────────────────────┐
┌─────────────┐ No │ │
│Parse Header ├────────────┤ Skip Nostr │
└──────┬──────┘ │ Validation │
│ │ │
▼ └──────────┬──────────┘
┌─────────────┐ ╔═══════════════════╗ │
│Valid Base64?├─No─►║ REJECT: Malformed ║ │
└──────┬──────┘ ║ Header (~10μs) ║ │
│Yes ╚═══════════════════╝ │
▼ │
┌─────────────┐ ╔═══════════════════╗ │
│Valid JSON? ├─No─►║ REJECT: Invalid ║ │
└──────┬──────┘ ║ JSON (~50μs) ║ │
│Yes ╚═══════════════════╝ │
▼ │
┌─────────────┐ ╔═══════════════════╗ │
│Valid Struct?├─No─►║ REJECT: Invalid ║ │
└──────┬──────┘ ║ Structure (~100μs)║ │
│Yes ╚═══════════════════╝ │
▼ │
┌─────────────┐ ╔═══════════════════╗ │
│Event Kind? │ ║ ║ │
└──────┬──────┘ ║ DUAL AUTH MODES ║ │
│ ╚═══════════════════╝ │
▼ │
┌─────────────────────────────────────────────────────┐
│ │
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Kind │ │ Kind │ │ Other │ │ Invalid │
│ 22242 │ │ 24242 │ │ Kinds │ │ Kind │
│ (NIP-42) │ │(Blossom) │ │ (Skip) │ │(Reject) │
└─────┬────┘ └─────┬────┘ └─────┬────┘ └─────┬────┘
│ │ │ │
▼ │ ▼ ▼
┌──────────┐ │ ┌──────────┐ ╔═══════════════════╗
│ NIP-42 │ │ │ Skip │ ║ REJECT: Invalid ║
│Challenge │ │ │ Nostr │ ║ Event Kind ║
│Validate │ │ │Validate │ ╚═══════════════════╝
│(~500μs) │ │ └─────┬────┘ │
└─────┬────┘ │ │ │
│ │ ▼ │
│ │ ┌──────────┐ │
│ │ │ Extract │ │
│ │ │ Context │ │
│ │ └─────┬────┘ │
│ │ │ │
▼ ▼ ▼ ▼
┌────────────────────────────────────────────────────────────┐
│ ECDSA SIGNATURE VERIFICATION │
│ (~2ms) │
└───────────────────────────┬────────────────────────────────┘
│Yes
▼ │
┌─────────────────┐ ╔═══════════════════╗
│Operation Match? │No ║ REJECT: Unauth. ║
│(Kind 24242 only)├──►║ Operation (~200μs)║
└─────────┬───────┘ ╚═══════════════════╝
│Yes/Skip(Kind 22242)
▼ │
┌─────────────────┐ ╔═══════════════════╗ │
│Event Expired? │Yes║ REJECT: Expired ║ │
└─────────┬───────┘ ║ Event (~50μs) ║ │
│No ╚═══════════════════╝ │
▼ │
┌─────────────────┐ │
│Extract Pubkey │ │
│& Auth Context │ │
└─────────┬───────┘ │
│ │
▼◄───────────────────────────────────────┘
┌─────────────────┐ ╔═══════════════════╗
│Auth Rules │ No ║ ALLOW: Rules ║
│Enabled? ├────►║ Disabled ║
└─────────┬───────┘ ╚═══════════════════╝
│Yes
▼
┌─────────────────┐
│Generate Cache │
│Key (SHA-256) │
└─────────┬───────┘
│
▼
┌─────────────────┐ ╔═══════════════════╗
│Cache Hit? │ Yes ║ RETURN: Cached ║
│(~100μs lookup) ├────►║ Decision (~100μs) ║
└─────────┬───────┘ ╚═══════════════════╝
│No
▼
╔═══════════════════════════════════════╗
║ RULE EVALUATION ENGINE ║
║ (Priority Order) ║
╚═══════════════════════════════════════╝
│
▼
┌─────────────────┐ ╔═══════════════════╗
│1. Pubkey │ Yes ║ DENY: Pubkey ║
│ Blacklisted? ├────►║ Blocked ║
└─────────┬───────┘ ╚═══════════════════╝
│No
▼
┌─────────────────┐ ╔═══════════════════╗
│2. Hash │ Yes ║ DENY: Hash ║
│ Blacklisted? ├────►║ Blocked ║
└─────────┬───────┘ ╚═══════════════════╝
│No
▼
┌─────────────────┐ ╔═══════════════════╗
│3. MIME Type │ Yes ║ DENY: MIME ║
│ Blacklisted? ├────►║ Blocked ║
└─────────┬───────┘ ╚═══════════════════╝
│No
▼
┌─────────────────┐ ╔═══════════════════╗
│4. Size Limit │ Yes ║ DENY: File ║
│ Exceeded? ├────►║ Too Large ║
└─────────┬───────┘ ╚═══════════════════╝
│No
▼
┌─────────────────┐ ╔═══════════════════╗
│5. Pubkey │ Yes ║ ALLOW: Pubkey ║
│ Whitelisted? ├────►║ Whitelisted ║
└─────────┬───────┘ ╚═══════════════════╝
│No
▼
┌─────────────────┐ ╔═══════════════════╗
│6. MIME Type │ Yes ║ ALLOW: MIME ║
│ Whitelisted? ├────►║ Whitelisted ║
└─────────┬───────┘ ╚═══════════════════╝
│No
▼
┌─────────────────┐ ╔═══════════════════╗
│Whitelist Rules │ Yes ║ DENY: Not in ║
│Exist? ├────►║ Whitelist ║
└─────────┬───────┘ ╚═══════════════════╝
│No
▼
╔═══════════════════╗
║ ALLOW: Default ║
║ Allow Policy ║
╚═══════════════════╝
│
▼
┌─────────────────┐
│ Cache Decision │
│ (5min TTL) │
└─────────┬───────┘
│
▼
┌─────────────────┐
│ Return Result │
│ to Application │
└─────────────────┘
Authentication Flow (Mermaid)
flowchart TD
A[Request Received] --> B{Input Valid?}
B -->|No| R1[REJECT: Invalid Input ~1μs]
B -->|Yes| C{System Init?}
C -->|No| R2[REJECT: Not Initialized]
C -->|Yes| D{Auth Header?}
D -->|No| SKIP[Skip Nostr Validation]
D -->|Yes| E{Valid Base64?}
E -->|No| R3[REJECT: Malformed Header ~10μs]
E -->|Yes| F{Valid JSON?}
F -->|No| R4[REJECT: Invalid JSON ~50μs]
F -->|Yes| G{Valid Struct?}
G -->|No| R5[REJECT: Invalid Structure ~100μs]
G -->|Yes| H{Event Kind?}
%% Event Kind Branching
H --> I[Kind 22242<br/>NIP-42]
H --> J[Kind 24242<br/>Blossom]
H --> K[Other Kinds<br/>Skip]
H --> L[Invalid Kind]
L --> R6[REJECT: Invalid Event Kind]
%% NIP-42 Path
I --> M[NIP-42 Challenge<br/>Validation ~500μs]
M --> N[ECDSA Signature<br/>Verification ~2ms]
%% Blossom Path
J --> N
%% Skip Path
K --> SKIP
SKIP --> O[Extract Context]
O --> N
%% Signature Verification
N -->|No| R7[REJECT: Invalid Signature ~2ms]
N -->|Yes| P{Operation Match?<br/>Kind 24242 only}
P -->|No| R8[REJECT: Unauthorized Operation ~200μs]
P -->|Yes/Skip 22242| Q{Event Expired?}
Q -->|Yes| R9[REJECT: Expired Event ~50μs]
Q -->|No| S[Extract Pubkey & Auth Context]
%% Rules Engine
S --> T{Auth Rules Enabled?}
T -->|No| ALLOW1[ALLOW: Rules Disabled]
T -->|Yes| U[Generate Cache Key SHA-256]
U --> V{Cache Hit?}
V -->|Yes| CACHED[RETURN: Cached Decision ~100μs]
V -->|No| W[RULE EVALUATION ENGINE<br/>Priority Order]
%% Rule Checks
W --> X1{1. Pubkey Blacklisted?}
X1 -->|Yes| DENY1[DENY: Pubkey Blocked]
X1 -->|No| X2{2. Hash Blacklisted?}
X2 -->|Yes| DENY2[DENY: Hash Blocked]
X2 -->|No| X3{3. MIME Blacklisted?}
X3 -->|Yes| DENY3[DENY: MIME Blocked]
X3 -->|No| X4{4. Size Limit Exceeded?}
X4 -->|Yes| DENY4[DENY: File Too Large]
X4 -->|No| X5{5. Pubkey Whitelisted?}
X5 -->|Yes| ALLOW2[ALLOW: Pubkey Whitelisted]
X5 -->|No| X6{6. MIME Whitelisted?}
X6 -->|Yes| ALLOW3[ALLOW: MIME Whitelisted]
X6 -->|No| X7{Whitelist Rules Exist?}
X7 -->|Yes| DENY5[DENY: Not in Whitelist]
X7 -->|No| ALLOW4[ALLOW: Default Policy]
%% Final Steps
ALLOW2 --> CACHE[Cache Decision 5min TTL]
ALLOW3 --> CACHE
ALLOW4 --> CACHE
DENY1 --> CACHE
DENY2 --> CACHE
DENY3 --> CACHE
DENY4 --> CACHE
DENY5 --> CACHE
CACHE --> RESULT[Return Result to Application]
%% Styling
classDef rejectBox fill:#ff4444,stroke:#ffffff,color:#ffffff
classDef allowBox fill:#44ff44,stroke:#ffffff,color:#000000
classDef processBox fill:#4444ff,stroke:#ffffff,color:#ffffff
classDef decisionBox fill:#ffff44,stroke:#000000,color:#000000
class R1,R2,R3,R4,R5,R6,R7,R8,R9,DENY1,DENY2,DENY3,DENY4,DENY5 rejectBox
class ALLOW1,ALLOW2,ALLOW3,ALLOW4,CACHED allowBox
class A,M,N,S,U,W,CACHE,RESULT,SKIP,O processBox
class B,C,D,E,F,G,H,P,Q,T,V,X1,X2,X3,X4,X5,X6,X7 decisionBox
Performance Timeline (ASCII)
Fast Path (Cache Hit) - Total: ~101μs
┌─────┬─────────────────────────────────────────────────────────────────┬──────┐
│ 1μs │ 100μs Cache Lookup │ 1μs │
└─────┴─────────────────────────────────────────────────────────────────┴──────┘
Input │ │ Return
Valid │ SQLite SELECT │ Result
Typical Path (Valid Request) - Total: ~2.4ms
┌──┬───┬────┬─────────────────────────┬────────┬────┬──┐
│1μ│50μ│100μ│ 2000μs │ 200μs │100μ│1μ│
└──┴───┴────┴─────────────────────────┴────────┴────┴──┘
│ │ │ │ │ │ │
│ │ │ │ ECDSA Signature │ Rule │Cache│Return
│ │ │ │ Verification │ Eval │Store│Result
│ │ │ │ (Most Expensive) │ │ │
│ │ │
│ │ JSON Parse
│ Header Parse
Input Validation
Worst Case (Full Validation) - Total: ~2.7ms
┌──┬───┬────┬─────────────────────────┬─────────┬────┬──┐
│1μ│50μ│100μ│ 2000μs │ 500μs │100μ│1μ│
└──┴───┴────┴─────────────────────────┴─────────┴────┴──┘
│
All 6 Rule Checks
(Multiple DB Queries)
Dual Authentication Architecture
The system supports two authentication modes that can work independently or together:
NIP-42 Authentication (Kind 22242)
- Purpose: Client identity authentication ("who you are")
- Use Case: Relay client authentication, WebSocket connections
- Event Structure: Contains
relayURL andchallengetags - Flow: Challenge/response pattern with relay-generated challenges
- Validation: Verifies client identity against relay URL and challenge
- Database Storage: Client sessions and challenge tracking
Blossom Protocol Authentication (Kind 24242)
- Purpose: Operation authorization ("what you can do")
- Use Case: File upload/delete/list operations
- Event Structure: Contains operation tag
t=upload|delete|listand content hashx=hash - Flow: Direct operation authorization with expiration
- Validation: Verifies operation permissions and content integrity
- Database Storage: Operation-specific authentication rules
Integration Strategy
┌─────────────────┐ ┌─────────────────┐
│ NIP-42 Auth │ │ Blossom Auth │
│ (Kind 22242) │ │ (Kind 24242) │
│ │ │ │
│ Client Identity │ │ Operation Perms │
│ Challenge/Resp │ │ File Operations │
└─────────┬───────┘ └─────────┬───────┘
│ │
└──────┬─────────┬─────┘
│ │
▼ ▼
┌─────────────────┐
│ Unified Rules │
│ Engine │
│ │
│ • Pubkey Rules │
│ • Hash Rules │
│ • MIME Rules │
│ • Size Limits │
└─────────────────┘
Event Kind Processing
- Kind 22242 (NIP-42): Validates against stored challenge + relay URL
- Kind 24242 (Blossom): Validates operation tags + content integrity
- Other Kinds: Skip Nostr validation, proceed to rule evaluation
- Invalid Kind: Reject immediately
Dual Mode Benefits
- Backwards Compatibility: Existing Blossom clients continue working
- Enhanced Security: NIP-42 provides cryptographic client identity
- Flexible Deployment: Relays can require either or both methods
- Performance: Separate validation paths optimize for each use case
Request Processing Flow (DDoS-Optimized)
The authentication system is designed with performance and DDoS protection as primary concerns. Here's the exact order of operations:
Phase 1: Input Validation (Immediate Rejection)
- Null Pointer Checks - Reject malformed requests instantly (lines 122-128)
- Initialization Check - Verify system is properly initialized
- Basic Structure Validation - Ensure required fields are present
Phase 2: Nostr Event Validation (CPU Intensive)
-
Authorization Header Parsing (lines 139-148)
- Extract base64-encoded Nostr event from
Authorization: Nostr <base64>header - Decode base64 to JSON (memory allocation + decoding)
- Early exit: Invalid base64 or malformed header rejected immediately
- Extract base64-encoded Nostr event from
-
JSON Parsing (lines 150-156)
- Parse Nostr event JSON using cJSON
- Early exit: Invalid JSON rejected before signature verification
-
Nostr Event Structure Validation (lines 159-166)
- Validate event has required fields (kind, pubkey, sig, etc.)
- Early exit: Invalid structure rejected before expensive crypto operations
-
Event Kind Routing (NEW - Dual Authentication)
- Kind 22242 (NIP-42): Route to NIP-42 challenge validation
- Kind 24242 (Blossom): Route to Blossom operation validation
- Other Kinds: Skip Nostr validation, proceed to rules
- Invalid Kind: Reject immediately
-
NIP-42 Challenge Validation (Kind 22242 Only)
- Validate
relaytag matches configured relay URL - Verify
challengetag exists and matches stored challenge - Check challenge expiration and single-use constraints
- Performance: ~500μs additional validation overhead
- Validate
-
Cryptographic Signature Verification (Both Paths)
- Most CPU-intensive operation - ECDSA signature verification
- Validates event authenticity using secp256k1
- Early exit: Invalid signatures rejected before database queries
-
Operation-Specific Validation (Kind 24242 Only)
- Verify event authorizes the requested operation (upload/delete/list)
- Check required tags (t=operation, x=hash, expiration)
- Validate timestamp and expiration
- Early exit: Expired or mismatched events rejected
-
Public Key Extraction (Both Paths)
- Extract validated public key from event for rule evaluation
- Store authentication context (NIP-42 vs Blossom) for rule processing
Phase 3: Authentication Rules (Database Queries)
-
Rules System Check (line 191)
- Quick config check if authentication rules are enabled
- Early exit: If disabled, allow request immediately
-
Cache Lookup (lines 1051-1054)
- Generate SHA-256 cache key from request parameters
- Check SQLite cache for previous decision
- Early exit: Cache hit returns cached decision (5-minute TTL)
-
Rule Evaluation (Priority Order - lines 1061-1094):
- a. Pubkey Blacklist (highest priority) - Immediate denial if matched
- b. Hash Blacklist - Block specific content hashes
- c. MIME Type Blacklist - Block dangerous file types
- d. File Size Limits - Enforce upload size restrictions
- e. Pubkey Whitelist - Allow specific users (only if not denied above)
- f. MIME Type Whitelist - Allow specific file types
-
Whitelist Default Denial (lines 1097-1121)
- If whitelist rules exist but none matched, deny request
- Prevents whitelist bypass attacks
-
Cache Storage (line 1124)
- Store decision in cache for future requests (5-minute TTL)
DDoS Protection Features
Fail-Fast Design
- Input validation happens before any expensive operations
- Authorization header parsing fails fast on malformed data
- JSON parsing rejects invalid data before signature verification
- Structure validation happens before cryptographic operations
Expensive Operations Last
- Signature verification only after structure validation
- Database queries only after successful Nostr validation
- Cache prioritized over database queries
Caching Strategy
- SHA-256 cache keys prevent cache pollution attacks
- 5-minute TTL balances performance with rule changes
- LRU eviction prevents memory exhaustion
- Per-request caching includes all parameters (pubkey, operation, hash, MIME, size)
Resource Limits
- JSON parsing limited to 4KB buffer size
- Cache entries limited to prevent memory exhaustion
- Database connection pooling (single connection with proper cleanup)
- String length limits on all inputs
Attack Mitigation
- Base64 bombs - Limited decode buffer size (4KB)
- JSON bombs - cJSON library handles malformed JSON safely
- Cache poisoning - Cryptographic cache keys prevent collisions
- Rule bypass - Whitelist default denial prevents unauthorized access
- Replay attacks - Timestamp and expiration validation
- Hash collision attacks - Full SHA-256 verification
Performance Characteristics
Best Case (Cached Decision):
- Input validation: ~1μs
- Cache lookup: ~100μs (SQLite SELECT)
- Total: ~101μs
Worst Case (Full Validation + Rule Evaluation):
- Input validation: ~1μs
- Base64 decoding: ~50μs
- JSON parsing: ~100μs
- Signature verification: ~2000μs (ECDSA)
- Database queries: ~500μs (6 rule checks)
- Cache storage: ~100μs
- Total: ~2751μs (~2.7ms)
Typical Case (Valid Request, Rules Enabled):
- Full validation: ~2200μs
- Cache miss, 2-3 rule checks: ~200μs
- Total: ~2400μs (~2.4ms)
Security Order Rationale
The rule evaluation order is specifically designed for security:
- Blacklists First - Immediate denial of known bad actors
- Resource Limits - Prevent resource exhaustion attacks
- Whitelists Last - Only allow after passing all security checks
- Default Deny - If whitelists exist but don't match, deny
This ensures that even if an attacker bypasses one layer, subsequent layers will catch the attack.