Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nats-io/nats-server/llms.txt

Use this file to discover all available pages before exploring further.

Authorization Overview

NATS Server authorization controls what authenticated users can publish and subscribe to. Permissions are granted at the subject level, providing fine-grained access control.

Permissions System

The permission system operates on two dimensions:
  1. Publish Permissions - Control which subjects a user can publish messages to
  2. Subscribe Permissions - Control which subjects a user can subscribe to
Each permission dimension supports:
  • Allow rules - Explicitly permit access to subjects
  • Deny rules - Explicitly prohibit access to subjects (override allow rules)

Basic Permission Structure

permissions {
  publish {
    allow: ["subject1", "subject2.>"]
    deny: ["subject2.admin"]
  }
  subscribe {
    allow: ["results.>", "_INBOX.>"]
    deny: ["results.internal.>"]
  }
}

Subject Permission Rules

Wildcards

NATS supports two wildcard types:
  • * - Matches a single token
  • > - Matches one or more tokens (must be last)
Examples:
permissions {
  publish {
    allow: [
      "events.*",        # events.login, events.logout
      "logs.app.>"       # logs.app.error, logs.app.info.user
    ]
  }
}

Deny Override

Deny rules always override allow rules:
permissions {
  publish {
    allow: ["data.>"]
    deny: ["data.sensitive.>"]
  }
}
This user can publish to data.public but NOT data.sensitive.passwords.

User-Level Permissions

Username/Password Users

authorization {
  users = [
    {
      user: "publisher"
      password: "$2a$11$..."
      permissions: {
        publish: ["events.>"]
        subscribe: []  # Cannot subscribe
      }
    }
    {
      user: "subscriber"
      password: "$2a$11$..."
      permissions: {
        publish: ["_INBOX.>"]
        subscribe: ["events.>"]
      }
    }
  ]
}

NKey Users

authorization {
  users = [
    {
      nkey: "UCKASD5KPQQYHB6KYD7RC62VZQN7VRU5NN2BKL7UFBQ3UBYAJQPVNHSQ"
      permissions: {
        publish: {
          allow: ["orders.>"]
          deny: ["orders.cancel"]
        }
        subscribe: {
          allow: ["results.>", "_INBOX.>"]
        }
      }
    }
  ]
}

Account-Based Authorization

Accounts provide complete isolation between groups of users.

Multi-Account Configuration

accounts {
  PROD: {
    users: [
      {
        user: "prod_user"
        password: "$2a$11$..."
        permissions: {
          publish: ["production.>"]
          subscribe: ["production.>"]
        }
      }
    ]
  }
  
  DEV: {
    users: [
      {
        user: "dev_user"
        password: "$2a$11$..."
        permissions: {
          publish: ["dev.>"]
          subscribe: ["dev.>"]
        }
      }
    ]
  }
}
Users in different accounts cannot communicate unless explicit account imports/exports are configured.

Account Isolation

Accounts provide:
  • Subject namespace isolation - production.orders in PROD is separate from production.orders in DEV
  • Resource isolation - Connection and subscription limits per account
  • Security boundaries - Complete separation between tenants

Response Permissions

Allow clients to respond to request-reply messages dynamically:
authorization {
  users = [
    {
      user: "service"
      password: "$2a$11$..."
      permissions: {
        publish: {}
        subscribe: ["requests.>"]
        responses: {
          max: 100        # Max responses allowed
          ttl: "10s"      # Response permission expires after 10s
        }
      }
    }
  ]
}

Response Permission Behavior

  1. User subscribes to requests.service
  2. Request arrives with reply subject _INBOX.abc123
  3. User granted temporary publish permission to _INBOX.abc123
  4. Permission expires after TTL or max messages reached

Default Response Limits

From source code (server/auth.go:256-261):
DEFAULT_ALLOW_RESPONSE_MAX_MSGS = 1
DEFAULT_ALLOW_RESPONSE_EXPIRATION = 2 * time.Minute

Permission Examples

Read-Only Consumer

{
  user: "consumer"
  password: "$2a$11$..."
  permissions: {
    publish: ["_INBOX.>"]  # Only reply subjects
    subscribe: ["events.>", "data.>"]
  }
}

Publisher-Only

{
  user: "publisher"
  password: "$2a$11$..."
  permissions: {
    publish: ["events.app.>"]
    subscribe: []  # No subscriptions allowed
  }
}

Request-Reply Service

{
  user: "api_service"
  password: "$2a$11$..."
  permissions: {
    subscribe: ["api.requests.>"]
    responses: {
      max: 1
      ttl: "30s"
    }
  }
}

Admin User

{
  user: "admin"
  password: "$2a$11$..."
  permissions: {
    publish: {
      allow: [">"]
      deny: ["$SYS.>"]
    }
    subscribe: {
      allow: [">"]
      deny: ["$SYS.>"]
    }
  }
}

Service-Specific Permissions

{
  user: "order_service"
  password: "$2a$11$..."
  permissions: {
    publish: {
      allow: [
        "orders.created",
        "orders.updated",
        "orders.cancelled"
      ]
    }
    subscribe: {
      allow: [
        "orders.commands.>",
        "_INBOX.>"
      ]
    }
  }
}

Connection Type Restrictions

Restrict users to specific connection types:
authorization {
  users = [
    {
      user: "mqtt_only"
      password: "$2a$11$..."
      allowed_connection_types: ["MQTT"]
      permissions: {
        publish: ["sensors.>"]
        subscribe: ["commands.>"]
      }
    }
  ]
}
Supported connection types:
  • STANDARD - Regular NATS clients
  • WEBSOCKET - WebSocket clients
  • LEAFNODE - Leaf node connections
  • MQTT - MQTT clients

Route Permissions

Control what subjects can be imported/exported between servers in a cluster:
cluster {
  name: "production"
  
  permissions: {
    import: {
      allow: ["public.>"]
      deny: ["public.internal.>"]
    }
    export: {
      allow: ["public.>"]
      deny: ["public.internal.>"]
    }
  }
}

Account Imports and Exports

Accounts can selectively share subjects:

Export from Account

accounts {
  SERVICE: {
    exports: [
      {stream: "service.api.>"}  # Public API
      {service: "service.request.>"}  # Request-reply service
    ]
  }
}

Import into Account

accounts {
  CLIENT: {
    imports: [
      {stream: {account: "SERVICE", subject: "service.api.>"}, prefix: "external.service"}
      {service: {account: "SERVICE", subject: "service.request.>"}, to: "service.req"}
    ]
  }
}

Permission Validation

From server/auth.go implementation:

Publish Check

  1. Check deny list first - if matched, reject
  2. If allow list empty, default permit
  3. If allow list exists, subject must match

Subscribe Check

  1. Check deny list first - if matched, reject
  2. If allow list empty, default permit
  3. If allow list exists, subject must match

Testing Permissions

Test permissions before deploying:
# Test publish permission
nats-cli pub test.subject "hello" --creds=user.creds

# Test subscribe permission
nats-cli sub test.subject --creds=user.creds

Best Practices

1. Principle of Least Privilege

Grant minimal required permissions:
# Good - Specific permissions
permissions: {
  publish: ["metrics.service1.>"]
  subscribe: ["config.service1.>"]
}

# Bad - Overly permissive
permissions: {
  publish: [">"]
  subscribe: [">"]
}

2. Use Deny Rules for Exceptions

permissions: {
  publish: {
    allow: ["logs.>"]
    deny: ["logs.sensitive.>"]
  }
}

3. Organize by Account

Separate environments and tenants:
accounts {
  PROD: { ... }
  STAGING: { ... }
  DEV: { ... }
}

4. Enable Response Permissions

For request-reply patterns:
responses: {
  max: 1
  ttl: "5s"
}