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:
- Validate
authTokenvia@suaveplan/auth. - Check that
publicKeymatches the identity inauthToken. - Verify
claimedCapabilitiesagainst the mesh's allowed capability set. - Issue a
CapabilityTokensigned 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
MeshTrustTokenthat authorizes relay between two meshes. - Tier 0 hosts verify
MeshTrustTokenbefore accepting backbone connections from another mesh's host. CrossMeshTrustValidatorcaches 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—MeshMembershipVerifiervalidatesauthTokenvia@suaveplan/authbefore allowing mesh join.NET-107—MeshMembershipVerifierchecks that the peer'spublicKeymatches the identity inauthToken.NET-108—CapabilityTokenIssuerissues tokens signed by the server that constrain tier and capabilities.NET-109—CapabilityTokenincludespeerId,meshId,tier,capabilities,issuedAt,expiresAt, andserverSignature.NET-110—CrossMeshTrustValidatorrejects relay between meshes unless a trust relationship is established.NET-111—CrossMeshTrustValidatorcaches trust decisions with a configurable TTL.NET-112— Tier 0 hosts verifyMeshTrustTokenbefore 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.