# 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. ```ts class MeshMembershipVerifier { constructor(options: { authProvider: AuthProvider; // from @suaveplan/auth meshId: string; serverPubKey: Uint8Array; }); verifyJoinRequest(request: JoinRequest): Promise; } 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. ```ts 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. ```ts 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 ```ts 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`. --- ## 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.