A community member asked how to carry an HTTP-style permission level, such as PermissionLevel: 10, on individual NATS messages and have NATS filter or authorize messages based on that value.
The short answer: NATS supports custom message headers, but NATS permissions are subject-based, not header-based. If you attach authorization metadata to a message header, your application code is responsible for reading that header and deciding what to do.
Yes. NATS supports custom message headers. They are conceptually similar to HTTP/MIME-style headers: key-value metadata carried with a message.
For example, using the NATS CLI you can publish a message with a custom header using -H:
nats pub foo.bar hello -H "PermissionLevel:10"Client libraries generally expose headers as part of the message or publish API. The exact API shape varies by language and client, so check the documentation for the client you are using.
For example, in Go you may encounter APIs that publish a message object containing a Header field. Other clients expose similar concepts using their own language conventions.
One caveat: NATS and JetStream use a set of reserved headers internally, conventionally prefixed with Nats- (for example, Nats-Msg-Id). When defining your own metadata, give custom headers distinct names and avoid that prefix so they do not collide with server- or JetStream-interpreted headers. A name like PermissionLevel is fine.
No. NATS server permissions apply at the subject level.
Subject permissions are configured per user: you can allow or deny a given user — and therefore any connection authenticated as that user — from publishing or subscribing to specific subjects, such as:
1users.get2users.create3orders.*4admin.>But NATS does not evaluate arbitrary message headers such as:
1PermissionLevel: 10as part of its built-in permission checks.
So a policy like the following is not something the NATS server enforces directly:
Allow this subscriber to receive messages only when
PermissionLevel >= 10.
If that metadata is in a message header, enforcement must happen outside the NATS server permission system.
NATS subscription routing is subject-based. JetStream consumer filtering is also based on stream and subject configuration, not arbitrary custom header comparisons.
So while a message can carry headers, those headers are not used by NATS as a general-purpose server-side filtering language.
If you need consumers to receive only certain categories of messages, subjects are usually the first design tool to consider.
If your existing system already has message-level metadata such as an integer permission level, you can carry that value as a NATS header:
1PermissionLevel: 10Then subscribers parse the header and decide whether to process, ignore, reject, or forward the message.
A simplified flow might look like this:
users.get with PermissionLevel: 10.PermissionLevel header.This approach can be useful when permission metadata is part of the business protocol and must travel with the message.
However, it has an important security tradeoff: the server is not enforcing that header policy for you. Any enforcement must be correct and consistent in every application that consumes the message. If publishers are not fully trusted, you also need to think carefully about who is allowed to set that header and whether the header value can be spoofed.
Because NATS permissions are subject-based, another approach is to encode meaningful access boundaries into the subject design.
For example, instead of a single subject with a header:
1users.get2PermissionLevel: 10You might consider subjects that reflect the authorization or routing boundary:
1perm.10.users.get2perm.20.users.getor perhaps a domain-oriented design:
1public.users.get2internal.users.get3admin.users.getThen NATS permissions can allow or deny publish and subscribe access to those subject patterns.
This has a clear benefit: the NATS server can enforce access to subjects. But it also has tradeoffs:
For many systems, coarse-grained authorization belongs naturally in subjects, while fine-grained business rules remain in application code.
If you are migrating from an HTTP gateway model, another option is to keep enforcement in a gateway or service boundary.
For example:
This keeps the server-side NATS permission model focused on which components can publish or subscribe to which subjects, while application-level policy remains in code designed for that purpose.
This pattern can be especially useful when you need to preserve existing authorization rules during a migration from HTTP request/response to NATS messaging.
A practical rule of thumb:
For an integer permission level, the right design depends on what that number means.
If it is mainly metadata that consumers use to decide how to process a message, a header may be reasonable.
If it represents a hard security boundary, relying only on consumers to discard unauthorized messages may not be sufficient. In that case, consider whether the boundary should be represented in the subject hierarchy, enforced before publish, or handled by a trusted service layer.
You can test custom headers with the NATS CLI like this:
nats sub foo.barIn another terminal:
nats pub foo.bar hello -H "PermissionLevel:10"The exact display and header access behavior depends on the tool or client you use to receive the message, but the published NATS message can carry that custom header.
In an application, the subscriber would need to inspect the message headers and apply its own rule, such as:
1if PermissionLevel >= requiredLevel:2 process message3else:4 ignore or reject messageThat comparison is application logic, not a NATS server permission check.
NATS custom headers are useful for carrying per-message metadata, including values similar to HTTP headers. But NATS does not provide built-in permissioning or filtering based on arbitrary header values.
If you need header-based authorization, implement it in your application or gateway. If you need the NATS server to enforce access, design your subject hierarchy and account/user permissions so that the authorization boundary is represented by subjects.
Want help from the NATS experts? Meet with our architects to get help tailored to your use case and environment.



News and content from across the community