Files
2026-05-27 23:29:53 +01:00

6.5 KiB

OpenSpec Change: network-plugin-auth

  • Change ID: network-plugin-auth
  • Package: @suaveplan/network-plugin-auth (new)
  • Status: PROPOSED
  • Date: 2026-05-01

Summary

Implement mesh membership authentication and cross-mesh relay authorization. The auth package exists in genesis (@suaveplan/auth) but provides generic OAuth/JWT/session primitives. There is no mesh-specific authentication: verifying that a peer is allowed to join a specific mesh, issuing capability tokens that constrain which tiers a peer can occupy, or validating trust relationships between meshes for relay traffic. This plugin bridges @suaveplan/auth into the mesh architecture.


Why

Current state: network-plugin-crypto-messages signs messages with Ed25519 and verifies server-signed session/mesh tokens. However, there is no authentication of the peer itself before it joins a mesh, no capability-based tier assignment, and no cross-mesh relay trust validation.

What's missing:

  • Peer authentication before joining a mesh
  • Mesh capability tokens (who can be Tier 0 vs Tier 1 vs Tier 2)
  • Cross-mesh relay authorization (which meshes trust each other)
  • Message integrity at relay hops

Core components

1. MeshMembershipVerifier

Verifies that a peer is authorized to join a mesh.

class MeshMembershipVerifier {
  constructor(options: {
    authProvider: AuthProvider; // from @suaveplan/auth
    meshId: string;
    serverPubKey: Uint8Array;
  });
  verifyJoinRequest(request: JoinRequest): Promise<JoinResult>;
}

interface JoinRequest {
  peerId: string;
  meshId: string;
  authToken: string; // JWT or opaque token from @suaveplan/auth
  publicKey: Uint8Array; // Ed25519 public key for future message verification
  claimedCapabilities: Capability[];
}

interface JoinResult {
  accepted: boolean;
  peerId: string;
  assignedTier: number; // 0, 1, or 2
  capabilityToken: CapabilityToken;
  reason?: string;
}

Verification steps:

  1. Validate authToken via @suaveplan/auth.
  2. Check that publicKey matches the identity in authToken.
  3. Verify claimedCapabilities against the mesh's allowed capability set.
  4. Issue a CapabilityToken signed by the server that constrains the peer's tier and permissions.

2. CapabilityTokenIssuer

Issues and validates capability tokens for mesh operations.

interface CapabilityToken {
  peerId: string;
  meshId: string;
  tier: number; // max tier this peer can occupy
  capabilities: Capability[];
  issuedAt: number;
  expiresAt: number;
  serverSignature: Uint8Array;
}

enum Capability {
  HOST = "host",           // can be Tier 0
  SUBHOST = "subhost",     // can be Tier 1
  RELAY = "relay",         // can act as intra-mesh relay
  BRIDGE = "bridge",       // can act as cross-mesh relay backbone
  AUDIT = "audit",         // can write to audit log
  CREATE_SESSION = "create_session",
  JOIN_SESSION = "join_session",
}

class CapabilityTokenIssuer {
  constructor(options: {
    serverKeyPair: Ed25519KeyPair;
    defaultTtlMs: number; // default 3600000 (1 hour)
  });
  issue(peerId: string, meshId: string, tier: number, capabilities: Capability[]): CapabilityToken;
  validate(token: CapabilityToken): boolean;
  renew(token: CapabilityToken): CapabilityToken;
}

3. CrossMeshTrustValidator

Validates trust relationships between meshes for relay traffic.

class CrossMeshTrustValidator {
  constructor(options: {
    trustStore: TrustStore; // meshId → trusted meshId set
    serverPubKey: Uint8Array;
  });
  validateRelay(sourceMeshId: string, targetMeshId: string): boolean;
  validateBackbone(hostId: string, meshId: string): boolean;
  addTrust(fromMeshId: string, toMeshId: string): void;
  removeTrust(fromMeshId: string, toMeshId: string): void;
}

interface TrustStore {
  getTrustedMeshes(meshId: string): string[];
  isTrusted(fromMeshId: string, toMeshId: string): boolean;
}

Trust model:

  • By default, meshes do NOT trust each other.
  • Trust is established by the central server signing a MeshTrustToken that authorizes relay between two meshes.
  • Tier 0 hosts verify MeshTrustToken before accepting backbone connections from another mesh's host.
  • CrossMeshTrustValidator caches trust decisions with TTL (default 5 minutes).

Error codes

const MESH_AUTH_CODES = defineCodes("MESH_AUTH", [
  "JOIN_REJECTED",
  "TOKEN_EXPIRED",
  "TOKEN_INVALID_SIGNATURE",
  "CAPABILITY_DENIED",
  "TIER_NOT_ALLOWED",
  "TRUST_NOT_ESTABLISHED",
  "BACKBONE_UNTRUSTED",
  "AUTH_PROVIDER_ERROR",
] as const);

MeshAuthError extends SuaveplanError<MeshAuthErrorCode>.


Dependencies

  • Consumes: @suaveplan/network (NetworkNode, NetworkBus), @suaveplan/auth (JWT validation, session management), @suaveplan/network-plugin-crypto-messages (Ed25519 signatures, server tokens), @suaveplan/network-plugin-registry (peer public keys), @suaveplan/error, @suaveplan/types, @opentelemetry/api.
  • Blocked on: network-core (shipped), network-plugin-crypto-messages, @suaveplan/auth.

Verification approach

  • src/verifier/verifier.spec-conformance.test.ts — pins join request validation, tier assignment, capability checks.
  • src/issuer/issuer.spec-conformance.test.ts — pins token issue/validate/renew, signature verification, expiry.
  • src/trust/trust-validator.spec-conformance.test.ts — pins trust store, relay validation, backbone validation, cache TTL.
  • tests/integration/auth.spec-conformance.test.ts — end-to-end: peer joins mesh, receives capability token, relay is validated.
  • 100/100/100/100 Istanbul coverage.

Conformance requirements (proposed)

  • NET-106 — MeshMembershipVerifier validates authToken via @suaveplan/auth before allowing mesh join.
  • NET-107 — MeshMembershipVerifier checks that the peer's publicKey matches the identity in authToken.
  • NET-108 — CapabilityTokenIssuer issues tokens signed by the server that constrain tier and capabilities.
  • NET-109 — CapabilityToken includes peerId, meshId, tier, capabilities, issuedAt, expiresAt, and serverSignature.
  • NET-110 — CrossMeshTrustValidator rejects relay between meshes unless a trust relationship is established.
  • NET-111 — CrossMeshTrustValidator caches trust decisions with a configurable TTL.
  • NET-112 — Tier 0 hosts verify MeshTrustToken before accepting backbone connections.

Out of scope

  • Fine-grained ACL per message type → v2; v1 uses capability tokens.
  • Revocation lists → v2; v1 relies on short token expiry.
  • Zero-knowledge proofs → future research.