Skip to content

Peer authorization

Michael edited this page Jan 15, 2026 · 4 revisions

The NATS permission model is relatively static. Permissions are assigned at client connection time.

The life cycle of services is not bound by the life time of permissions. This makes it hard to handle services appearing dynamically. To handle them, you had to design static subject hierarchies matching permission models. This is ok, but hierarchies are single dimensional and you often want to structure them according to their usage domain.

Traditional request/response are typically performing authorization on the responder side and authentication in the framework connecting requester and responder. This is not easily possible in NATS, because the responder does not know the requester. This authentication had to be implemented in the application protocol.

My peer authorization model provides subscribers with the identity of the publisher, allowing them to verify the credibility of the sender (for pub/sub) or authorize the requester.

The identity is provided in a special message header, that is injected upon receiving an incoming message. This is conceptually similar to a bearer token provided by an authenticating proxy. If a message traverses multiple NATS server supporting this mechanism, each one prepends such a header. Each transition between NATS server represent a trust domain, the recipient can trace this back.

This mechanism also allows a NATS server to implement a reliable isolation of INBOXes for responders, without explicit involvement or configuration of involved clients.

This is not yet implemented.

Brainstorming

Identity Format

  system:mechanism:user-name:roles:details
    │       │          │       │      │
    │       │          │       │      └─ JWT claims, TLS CN/SAN, UDS expressions...
    │       │          │       └─ role1,role2 (from ROLE rules)
    │       │          └─ from USER rule name
    │       └─ UDS/TLS/JWT/NKEY/MQTT
    └─ cluster or server name

Examples:

  • prod:UDS:alice:developers,admins:uid=1000
  • prod:TLS:bob:readonly:CN=bob@example.com,O=ACME
  • prod:JWT:service-x:api-access:iss=auth.example.com,sub=svc123

Design Notes

Using Message Headers

The choice of using message headers is questionable, because these are currently owned by clients only (the server does not read or modify them AFAIK). The alternative is to use a protocol header. However that would be a breaking change requiring client protocol support. Headers are less intrusive, but require some uniqueness criteria and might break clients that use fragile header processing.

Another issue is that this is the hot path. Injecting headers should not involve allocations or memory copy operations, to avoid negatively impacting the performance.

Message Volume

The size of an identity header can impact performance and bandwidth for tiny messages or messages traversing servers collecting an identity trace. To avoid a disproportional penalty, peer authentication needs to provide a configuration option:

  • Limit generation of identity headers based on subjects
  • Choose different identity formats (JWT may be huge) or types
  • Limit identity generation to local clients (vs. server connections)
  • Replace trace identities instead of prepending to them

Trust Zones and Signatures

A (sub/resp) client connected to a server using peer identities necessarily has to trust the server to have authenticated the connecting client and authorized the client to publish a message to the receiving subject.

An identity provided by a remote server can only be trusted:

  • if the chain of servers is trusted in its entirety,
  • or if the remote server signed the identity.

A remotely signed identity can only be trusted independently if the receiving client can verify the signature.

Ideally, a server should provide a client a trust zone topology specifying:

  • A mapping of identities to application trust zones (who is this identity in the context of an application)
  • Trust level of identities (protection from forgery/impersonation)
  • Expose based on message paths (network traversal, etc.)
  • Subject tree exposure (where is a subject visible: local, cluster, exports, etc.)

Clone this wiki locally