Configuration Reference
Standard go templating is used to construct roles dynamically. Templating functions are listed in the filters module.
The configuration structure is outlined below.
CLI
The broker uses subcommands:
nats-iam-broker serve [flags] config1.yaml [config2.yaml ...]
nats-iam-broker decrypt [flags] <token>
nats-iam-broker versionServe Flags
| Flag | Default | Description |
|---|---|---|
--log-level |
info |
Set log level: disabled, panic, fatal, error, warn, info, debug, trace |
--log-format |
json |
Set log format: json, human |
--log-sensitive |
false |
Enable sensitive logging (for debugging) |
--metrics |
false |
Enable Prometheus metrics endpoint |
--metrics-port |
8080 |
Port for the metrics HTTP server |
--watch |
false |
Enable hot-reload of config files via file watching |
CLI flags override values from the YAML configuration. The merge order is: defaults < YAML < CLI flags.
Hot-Reload
The broker supports hot-reloading configuration files without restarting. When enabled with the --watch flag, the broker watches config files for changes and atomically swaps to the new configuration.
nats-iam-broker serve --watch config.yamlWhat gets reloaded: IDP configuration, RBAC role bindings and roles, template expressions, custom claim mappings, and token expiry bounds.
What requires a restart: service.creds_file and service.account.signing_nkey (NATS connection identity). A warning is logged if these change.
Behavior:
- Debounced — rapid file changes (e.g., editor save) are coalesced into a single reload (500ms window).
- Validated — the new config is fully parsed and validated before swapping. Invalid configs are rejected and the previous config remains active.
- Kubernetes-friendly — watches parent directories to handle ConfigMap symlink rotations.
- Thread-safe — in-flight auth requests complete with the previous config; new requests use the updated config.
Multi-File Configuration Merging
When multiple configuration files are provided, they are merged in order using the following rules:
- Maps are merged recursively — keys from both files are preserved, and overlapping map values are merged depth-first.
- Arrays are concatenated, not replaced — if both files define an array for the same key (e.g.,
role_binding,roles,idp), the arrays are joined with the base file’s entries first, followed by the overlay file’s entries. - Primitives (strings, numbers, booleans) are overridden by the later file.
Because arrays are concatenated, splitting array-typed fields (like idp or rbac.role_binding) across multiple config files will produce a combined list — not a replacement. If you need to fully replace an array, define it in a single file.
Server Configuration
These settings live under server: in the YAML config. They can also be set via CLI flags on the serve subcommand.
| Key | Type | Default | Description |
|---|---|---|---|
server.log_level |
string |
info |
Log level: disabled, panic, fatal, error, warn, info, debug, trace |
server.log_format |
string |
json |
Log format: json, human |
server.log_sensitive |
bool |
false |
Enable sensitive logging (for debugging) |
server.metrics |
bool |
false |
Enable Prometheus metrics endpoint |
server.metrics_port |
int |
8080 |
Port for the metrics HTTP server |
server.watch |
bool |
false |
Enable hot-reload of config files via file watching |
NATS Configuration
| Key | Type | Default | Description |
|---|---|---|---|
nats.url |
string |
- | NATS server URL (required) |
nats.jwt_expiry_bounds.min |
duration |
1m |
Minimum lifetime for minted NATS JWTs |
nats.jwt_expiry_bounds.max |
duration |
1h |
Maximum lifetime for minted NATS JWTs |
Service Configuration
| Key | Type | Description |
|---|---|---|
service.name |
string |
Name of deployed micro-service instance (required) |
service.version |
string |
Version of deployed micro-service instance (required, semver) |
service.description |
string |
Description of deployed micro-service instance (required) |
service.creds_file |
string |
User credentials file used to connect to NATS (required) |
Account Configuration
| Key | Type | Description |
|---|---|---|
service.account.name |
string |
(metadata) human-readable reminder of account used to sign and encrypt communications with NATS server |
service.account.signing_nkey |
string |
Key used to sign new user-jwt returned to NATS (required) |
service.account.xkey_seed |
string |
xkey seed for encrypted communication with NATS server (encryption is enabled when set) |
IDP Configuration
| Key | Type | Description |
|---|---|---|
idp[].issuer_url |
string |
The URL of the IdP issuer (required) |
idp[].client_id |
string |
The client identifier registered with the IdP (required) |
idp[].description |
string |
Human-readable description of this IDP |
idp[].custom_mapping |
map[string]string |
Maps custom IDP claim names to standardized claim names (e.g. "https://example.com/claims/roles": "roles") |
idp[].ignore_setup_error |
bool |
If true, logs errors during the initial setup/verification of this IDP (e.g., connection errors to issuer_url) but allows the broker to start with other valid IDPs. Defaults to false. |
idp[].user_info.enabled |
bool |
If true, fetches additional claims from the OIDC UserInfo endpoint and merges them into the matching context. Requires the client to provide an access_token. |
idp[].max_token_lifetime |
duration |
Maximum allowed lifetime for incoming IDP tokens. Tokens with an expiry further in the future than this duration from now are rejected. Defaults to 24h. |
idp[].clock_skew |
duration |
Allowed clock skew when validating IDP token iat and exp timestamps. Defaults to 5m. |
IDP Validation
| Key | Type | Description |
|---|---|---|
idp[].validation.claims |
[]string |
Set of required claims on idp token |
idp[].validation.aud |
[]string |
Set of allowed values for audience claim |
idp[].validation.skip_audience_validation |
bool |
If true, skip audience validation for this IDP |
idp[].validation.token_bounds.min |
duration |
Minimum time to expiry for idp token from now |
idp[].validation.token_bounds.max |
duration |
Maximum duration of idp token from now |
idp[].token_bounds.min |
duration |
Per-IDP override for minted JWT minimum lifetime |
idp[].token_bounds.max |
duration |
Per-IDP override for minted JWT maximum lifetime |
Token Expiry
The expiry of the issued NATS JWT is determined by the following rules, applied in order:
- IDP-provided expiry — the
expclaim from the incoming IdP token is used as the starting value. - IDP validation bounds (
idp[].validation.token_bounds.min/.max) — if configured, the expiry is raised to the min or lowered to the max. - Role binding override (
rbac.role_binding[i].token_max_expiration) — if set on the matched binding, overrides the expiry to this duration from now. - RBAC default (
rbac.token_max_expiration) — if no role binding override is set and this is configured, the expiry is capped at this duration from now. - NATS JWT expiry bounds (
nats.jwt_expiry_bounds.min/.max) — the final expiry is clamped within these bounds. - IDP ceiling — the IDP-provided expiry is enforced as an absolute upper bound. No override (role binding, RBAC, or NATS bounds) may extend the issued token beyond the lifetime the IDP originally granted.
The IDP ceiling ensures that the broker never issues a NATS token that outlives the upstream IdP token. This is a security invariant: if the IdP granted a 30-minute token, the NATS JWT will never exceed 30 minutes regardless of other configuration.
RBAC Configuration
| Key | Type | Description |
|---|---|---|
rbac.token_max_expiration |
duration |
Default maximum expiry for minted NATS JWTs. Overridden by per-binding token_max_expiration. |
rbac.role_binding_matching_strategy |
string |
Strategy for selecting a role binding when multiple could match. strict or best_match. Defaults to best_match. See Matching Strategies. |
rbac.auto_accounts_dir |
string |
Optional. Directory to scan for *-id-1.pub / *-sk-1.nk file pairs to auto-discover user accounts. |
rbac.user_accounts |
- | Set of accounts configured to issue and sign nats user-jwts |
rbac.user_accounts[i].name |
string |
Name of user-jwt signing account |
rbac.user_accounts[i].public_key |
string |
Public key of user-jwt signing account |
rbac.user_accounts[i].signing_nkey |
string |
Signing key of user-jwt signing account in nkey format |
rbac.roles |
- | Set of referenceable nats jwt permission groupings |
rbac.roles[i].name |
string |
Role name |
rbac.roles[i].permissions |
jwt.Permissions | nats-io/jwt permissions structure (see link) |
rbac.roles[i].limits |
jwt.Limits | nats-io/jwt limits structure (see link) |
Role Binding Configuration
| Key | Type | Description |
|---|---|---|
rbac.role_binding |
- | Defines how IdP claims/permissions map to user accounts and roles |
rbac.role_binding[i].user_account |
string |
User account (from rbac.user_accounts) to issue the NATS JWT from |
rbac.role_binding[i].roles |
[]string |
Set of roles (from rbac.roles) whose permissions and limits are assigned to the NATS JWT |
rbac.role_binding[i].token_max_expiration |
duration |
Override token max expiry for this binding. Overrides rbac.token_max_expiration. |
rbac.role_binding[i].match |
[]Match |
List of criteria that must be met in the IdP JWT for this binding to be considered |
rbac.role_binding[i].match[j].claim |
string |
Name of an IdP JWT claim to match on (e.g., “email”, “groups”). Required if permission and expr are not set. |
rbac.role_binding[i].match[j].value |
string |
The value the corresponding IdP JWT claim must have. Required if claim is set. |
rbac.role_binding[i].match[j].permission |
string |
A permission string required in the IdP JWT’s permissions claim. Required if claim and expr are not set. |
rbac.role_binding[i].match[j].expr |
string |
A boolean expression evaluated against all available claims using expr-lang/expr. See Role Binding & Matching. |