Files
natsdotnet/docs/plans/2026-02-23-mqtt-connection-type-design.md

6.6 KiB

MQTT Connection Type Port Design

Goal

Port MQTT-related connection type parity from Go into the .NET server for three scoped areas:

  1. JWT allowed_connection_types behavior for MQTT / MQTT_WS (plus existing known types).
  2. /connz filtering by mqtt_client.
  3. Full MQTT configuration parsing from mqtt {} config blocks (all Go MQTTOpts fields).

Scope

  • In scope:
    • JWT allowed connection type normalization and enforcement semantics.
    • /connz?mqtt_client= option parsing and filtering.
    • MQTT configuration model and config file parsing (all Go MQTTOpts fields).
    • Expanded MqttOptsVarz monitoring output.
    • Unit/integration tests for new and updated behavior.
    • differences.md updates after implementation is verified.
  • Out of scope:
    • Full MQTT transport implementation (listener, protocol parser, sessions).
    • WebSocket transport implementation.
    • Leaf/route/gateway transport plumbing.

Architecture

  • Add an auth-facing connection-type model that can be passed through ClientAuthContext.
  • Implement Go-style allowed connection type conversion and matching in JwtAuthenticator:
    • normalize input to uppercase.
    • retain recognized types.
    • collect unknown types as non-fatal if at least one valid type remains.
    • reject when only unknown types are present.
    • enforce current connection type against the resulting allowed set.
  • Extend connz monitoring options to parse mqtt_client and apply exact-match filtering before sort/pagination.

Components

JWT Connection-Type Enforcement

  • src/NATS.Server/Auth/IAuthenticator.cs
    • Extend ClientAuthContext with a connection-type value.
  • src/NATS.Server/Auth/Jwt/JwtConnectionTypes.cs (new)
    • Canonical constants for known connection types:
      • STANDARD, WEBSOCKET, LEAFNODE, LEAFNODE_WS, MQTT, MQTT_WS, INPROCESS.
    • Helper(s) for normalization and validation behavior.
  • src/NATS.Server/Auth/JwtAuthenticator.cs
    • Evaluate userClaims.Nats?.AllowedConnectionTypes using Go-compatible semantics.
    • Enforce against current ClientAuthContext.ConnectionType.
  • src/NATS.Server/NatsClient.cs
    • Populate auth context connection type (currently STANDARD).

Connz MQTT Client Filtering

  • src/NATS.Server/Monitoring/Connz.cs
    • Add MqttClient to ConnzOptions with JSON field mqtt_client.
  • src/NATS.Server/Monitoring/ConnzHandler.cs
    • Parse mqtt_client query param.
    • Filter connection list by exact MqttClient match when provided.
  • src/NATS.Server/Monitoring/ClosedClient.cs
    • Add MqttClient field to closed snapshots.
  • src/NATS.Server/NatsServer.cs
    • Persist MqttClient into ClosedClient snapshot (empty for now).

MQTT Configuration Parsing

  • src/NATS.Server/MqttOptions.cs (new)
    • Full model matching Go MQTTOpts struct (opts.go:613-707):
      • Network: Host, Port
      • Auth override: NoAuthUser, Username, Password, Token, AuthTimeout
      • TLS: TlsCert, TlsKey, TlsCaCert, TlsVerify, TlsTimeout, TlsMap, TlsPinnedCerts
      • JetStream: JsDomain, StreamReplicas, ConsumerReplicas, ConsumerMemoryStorage, ConsumerInactiveThreshold
      • QoS: AckWait, MaxAckPending, JsApiTimeout
  • src/NATS.Server/NatsOptions.cs
    • Add Mqtt property of type MqttOptions?.
  • src/NATS.Server/Configuration/ConfigProcessor.cs
    • Add ParseMqtt() for mqtt {} config block with Go-compatible key aliases:
      • host/net → Host, listen → Host+Port
      • ack_wait/ackwait → AckWait
      • max_ack_pending/max_pending/max_inflight → MaxAckPending
      • js_domain → JsDomain
      • js_api_timeout/api_timeout → JsApiTimeout
      • consumer_inactive_threshold/consumer_auto_cleanup → ConsumerInactiveThreshold
      • Nested tls {} and authorization {}/authentication {} blocks
  • src/NATS.Server/Monitoring/Varz.cs
    • Expand MqttOptsVarz from 3 fields to full monitoring-visible set.
  • src/NATS.Server/Monitoring/VarzHandler.cs
    • Populate expanded MqttOptsVarz from NatsOptions.Mqtt.

Data Flow

  1. Client sends CONNECT.
  2. NatsClient.ProcessConnectAsync builds ClientAuthContext with ConnectionType=STANDARD.
  3. AuthService invokes JwtAuthenticator for JWT-based auth.
  4. JwtAuthenticator:
    • converts allowed_connection_types to valid/unknown buckets.
    • rejects unknown-only lists.
    • enforces connection-type membership when valid list is non-empty.
  5. Monitoring request /connz:
    • ConnzHandler.ParseQueryParams reads mqtt_client.
    • open/closed conn rows are materialized.
    • rows are filtered on exact MqttClient when filter is present.
    • sorting and pagination run on filtered results.

Error Handling and Compatibility

  • Auth failures remain non-throwing (Authenticate returns null).
  • Unknown connection type tokens in JWT are tolerated only when at least one known allowed type remains.
  • Unknown-only allowed lists are rejected to avoid unintended allow-all behavior.
  • mqtt_client query parsing is lenient and string-based; empty filter means no filter.
  • Existing JSON schema compatibility is preserved.

Current Runtime Limitation (Explicit)

  • MQTT transport is not implemented yet in this repository.
  • Runtime connection type currently resolves to STANDARD in auth context.
  • mqtt_client values remain empty until MQTT path populates them.
  • MQTT config is parsed and stored but no listener is started.

Testing Strategy

  • tests/NATS.Server.Tests/JwtAuthenticatorTests.cs
    • allow STANDARD for current client context.
    • reject MQTT for current client context.
    • allow mixed known+unknown when current type is known allowed.
    • reject unknown-only list.
    • validate case normalization behavior.
  • tests/NATS.Server.Tests/MonitorTests.cs
    • /connz?mqtt_client=<id> returns matching connections only.
    • /connz?state=closed&mqtt_client=<id> filters closed snapshots.
    • non-existing ID yields empty connection set.
  • tests/NATS.Server.Tests/ConfigProcessorTests.cs (or similar)
    • Parse valid mqtt {} block with all fields.
    • Parse config with aliases (ackwait vs ack_wait, host vs net, etc.).
    • Parse nested tls {} and authorization {} blocks within mqtt.
    • Varz MQTT section populated from config.

Success Criteria

  • JWT allowed_connection_types behavior matches Go semantics for known/unknown mixing and unknown-only rejection.
  • /connz supports exact mqtt_client filtering for open and closed sets.
  • mqtt {} config block parses all Go MQTTOpts fields with aliases.
  • MqttOptsVarz includes full monitoring output.
  • Added tests pass.
  • differences.md accurately reflects implemented parity.