Skip to main content

Overview

Accounts provide strong multi-tenancy in NATS by creating isolated subject namespaces. Each account maintains complete isolation from other accounts unless explicitly configured to share specific streams or services.

Multi-Tenancy with Accounts

From server/accounts.go:50-52, an Account represents a subject namespace definition where:
  • Messages published in one account cannot be seen by other accounts
  • Subscriptions exist within account boundaries
  • Sharing occurs only through explicit exports and imports
  • Each account has independent limits and quotas

The Global Account

From server/accounts.go:42-44, for backward compatibility with NATS < 2.0:
const globalAccountName = DEFAULT_GLOBAL_ACCOUNT
Users not explicitly assigned to an account are placed in the global account. In modern deployments, you should explicitly define accounts rather than relying on the global account.

Account Structure

From server/accounts.go:52-119, each account maintains:
  • Sublist (sl): Subscription matching tree
  • Client tracking: Maps of connected clients
  • Statistics: Message and byte counters for different connection types
  • Import/Export maps: Cross-account sharing configuration
  • JetStream context: Optional per-account JetStream resources
  • Limits: Connection, subscription, and payload limits
  • Permissions: Default permissions for account users

Account Isolation and Security Boundaries

Subject Space Isolation

Each account has its own subject space:
Account A:                    Account B:
  orders.created               orders.created
  users.login                  users.login  
  inventory.update             inventory.update
These are completely separate - a message published to orders.created in Account A will never reach subscribers in Account B (unless explicitly exported/imported).

Resource Isolation

From server/accounts.go:53-60, accounts track separate statistics:
stats struct {
    sync.Mutex
    stats       // Totals
    gw    stats // Gateways
    rt    stats // Routes  
    ln    stats // Leafnodes
}
Each account tracks:
  • Messages in/out
  • Bytes in/out
  • Slow consumers
  • Per-connection-type breakdowns

Connection Isolation

Clients connect to specific accounts:
  • User credentials determine account assignment
  • Each client belongs to exactly one account
  • Client can only publish/subscribe within their account
  • Cross-account access only via explicit imports/exports

System Account

The system account is a special privileged account used for monitoring and management.

System Account Role

From server/server.go:192, the server maintains a reference to the system account:
sys                 *internal
sysAcc              atomic.Pointer[Account]
The system account:
  • Receives server events and metrics
  • Provides monitoring endpoints
  • Handles server-to-server communication
  • Cannot be used for regular application messaging

System Account Configuration

accounts {
  SYS: {
    users: [
      {user: "admin", password: "admin_pass"}
    ]
  }
  APP: {
    users: [
      {user: "app", password: "app_pass"}
    ]
  }
}

system_account: "SYS"
Never use the system account for application traffic. It has special privileges and bypass certain limits.

System Account Events

The system account receives:
  • Connection events: $SYS.ACCOUNT.*.CONNECT
  • Disconnect events: $SYS.ACCOUNT.*.DISCONNECT
  • Server stats: $SYS.SERVER.*.STATSZ
  • JetStream advisories: $JS.EVENT.ADVISORY.>
Subscribe to these subjects in the system account for monitoring.

JWT-Based Authentication

NATS supports decentralized authentication using JSON Web Tokens (JWTs).

JWT Architecture

From server/accounts.go:36 and server/auth.go:33:
import (
    "github.com/nats-io/jwt/v2"
    "github.com/nats-io/nkeys"
)
JWT authentication uses:
  • Operator JWT: Root of trust, signs accounts
  • Account JWT: Defines account properties and limits
  • User JWT: Credentials for individual users
  • NKeys: Ed25519 key pairs for signing and verification

JWT Components

From server/accounts.go:64-66:
Nkey         string
Issuer       string  
claimJWT     string
Each account stores:
  • Nkey: Account’s public key
  • Issuer: Operator’s public key that signed this account
  • claimJWT: The full JWT claim

Signing Keys

From server/accounts.go:98-99:
signingKeys  map[string]jwt.Scope
extAuth      *jwt.ExternalAuthorization
Accounts support:
  • Multiple signing keys: Rotate keys without downtime
  • Scoped keys: Limit what each signing key can authorize
  • External authorization: Delegate authentication to external services

JWT Configuration

Enable JWT mode:
operator: "/path/to/operator.jwt"
resolver: {
  type: "full"
  dir: "/path/to/jwt/storage"
}
Or use URL resolver:
operator: "/path/to/operator.jwt"  
resolver: "URL(http://jwt-resolver.example.com:8080/jwt/v1/accounts/)" 

User Credentials

Users authenticate with credential files:
-----BEGIN NATS USER JWT-----
eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5...
------END NATS USER JWT------

************************* IMPORTANT *************************
NKEY Seed printed below can be used to sign and prove identity.
    NKEYs are sensitive and should be treated as secrets.

-----BEGIN USER NKEY SEED-----
SUACCSSUZZMCJWVYW3OEQZ6NNFMWP...
------END USER NKEY SEED------
Clients load credentials:
nc, err := nats.Connect("nats://localhost:4222",
    nats.UserCredentials("/path/to/user.creds"))

Account Limits and Quotas

From server/accounts.go:126-133, accounts support limits:
type limits struct {
    mpay           int32  // Max payload size
    msubs          int32  // Max subscriptions
    mconns         int32  // Max connections  
    mleafs         int32  // Max leaf node connections
    disallowBearer bool   // Disallow bearer tokens
}

Connection Limits

Limit the number of connections per account:
accounts {
  APP: {
    users: [{user: "app", password: "pass"}]
    limits: {
      max_connections: 1000
      max_leafnodes: 10
    }
  }
}
From server/accounts.go:77-80, the server tracks:
nrclients    int32  // Number of remote clients
sysclients   int32  // Number of system clients  
nleafs       int32  // Number of leaf nodes
nrleafs      int32  // Number of remote leaf nodes

Subscription Limits

Limit subscriptions per account:
accounts {
  APP: {
    users: [{user: "app", password: "pass"}]
    limits: {
      max_subscriptions: 10000
    }
  }
}
Exceeding limits results in client errors.

Payload Size Limits

Limit maximum message size:
accounts {
  APP: {
    users: [{user: "app", password: "pass"}]
    limits: {
      max_payload: 1048576  # 1MB
    }
  }
}
From server/server.go:123, the server advertises max payload:
MaxPayload        int32    `json:"max_payload"`

JetStream Limits

From server/accounts.go:93:
jsLimits     map[string]JetStreamAccountLimits
JetStream limits per account:
accounts {
  APP: {
    jetstream: {
      max_memory: 1073741824      # 1GB
      max_file: 10737418240       # 10GB  
      max_streams: 100
      max_consumers: 1000
    }
  }
}

Exports and Imports

Accounts can selectively share streams or services.

Stream Exports

From server/accounts.go:142-150, stream imports:
type streamImport struct {
    acc     *Account
    from    string           // Remote subject
    to      string           // Local subject
    tr      *subjectTransform
    claim   *jwt.Import
    usePub  bool
    invalid bool
}
Export a stream:
accounts {
  ORDERS: {
    exports: [
      {stream: "orders.>"}
    ]
  }
  
  FULFILLMENT: {
    imports: [
      {stream: {account: "ORDERS", subject: "orders.>"}, prefix: "external.orders"}
    ]
  }
}
Messages published to orders.shipped in ORDERS appear as external.orders.shipped in FULFILLMENT.

Service Exports

Export request-reply services:
accounts {
  AUTH: {
    exports: [
      {service: "auth.validate"}
    ]
  }
  
  APP: {
    imports: [
      {service: {account: "AUTH", subject: "auth.validate"}}
    ]
  }
}
APP can send requests to auth.validate which are handled by AUTH account services.

Subject Transforms

From server/accounts.go:146-147, imports support transformations:
tr      *subjectTransform
rtr     *subjectTransform  // Reverse transform
Transform subjects during import:
imports: [
  {
    stream: {account: "SOURCE", subject: "old.>"}
    to: "new.>"  # Maps old.foo -> new.foo
  }
]

Account Management

Static Configuration

Define accounts in configuration file:
accounts {
  ACCOUNT_A: {
    users: [
      {user: "user_a", password: "pass_a"}
    ]
  }
  ACCOUNT_B: {
    users: [
      {user: "user_b", password: "pass_b"}  
    ]
  }
}

JWT-Based Management

Use JWT resolver for dynamic account management:
  1. Create operator and signing key
  2. Issue account JWTs signed by operator
  3. Issue user JWTs signed by account
  4. Configure server with operator JWT and resolver
  5. Server fetches account JWTs from resolver as needed
This enables:
  • Adding accounts without server restart
  • Updating account limits dynamically
  • Revoking user credentials
  • Account delegation

Account Revocation

From server/accounts.go:84:
usersRevoked map[string]int64
Revoke user credentials:
nsc revocations add_user --account ACCOUNT --user-public-key NKEY
Revoked users are immediately disconnected.

Account Updates

From server/accounts.go:67:
updated      time.Time
With JWT resolver:
  • Server periodically checks for account updates
  • Updated JWTs apply to new connections immediately
  • Existing connections use permissions from connection time
  • Can force disconnect for immediate updates

Account Best Practices

Account Design

  1. One account per tenant: Isolate customers completely
  2. System account separation: Never mix application and monitoring
  3. Service accounts: Dedicated accounts for shared services
  4. Environment separation: Separate dev/staging/prod accounts

Security

  1. Use JWT authentication: Centralized, revocable credentials
  2. Set appropriate limits: Prevent resource exhaustion
  3. Minimal exports: Only share what’s necessary
  4. Audit imports: Know what external data you consume
  5. Rotate signing keys: Regular key rotation for security

Performance

  1. Account-level optimization: Some routes can be account-dedicated
  2. Limit account count: Many accounts increase overhead
  3. Monitor account metrics: Track per-account resource usage
  4. Subject planning: Design subjects for efficient routing

Operations

  1. Use JWT resolver: Enable dynamic account management
  2. Monitor system account: Subscribe to server events
  3. Set up alerts: Track limit violations
  4. Document exports: Maintain export/import relationships
  5. Test failover: Verify account isolation during failures

Monitoring Accounts

Account Statistics

From server monitoring endpoints:
  • /accountz: List all accounts and basic stats
  • /connz?acc=ACCOUNT: Connections for specific account
  • /subsz?acc=ACCOUNT: Subscriptions for specific account

System Account Monitoring

Subscribe in system account:
// Connection tracking
nc.Subscribe("$SYS.ACCOUNT.*.CONNECT", func(m *nats.Msg) {
    // Log connections
})

// Account statistics  
nc.Subscribe("$SYS.REQ.ACCOUNT.*.STATSZ", func(m *nats.Msg) {
    // Process account stats
})

JetStream Account Monitoring

For accounts with JetStream:
// Stream events
nc.Subscribe("$JS.EVENT.ADVISORY.STREAM.*", func(m *nats.Msg) {
    // Track stream operations
})

// Consumer events  
nc.Subscribe("$JS.EVENT.ADVISORY.CONSUMER.*", func(m *nats.Msg) {
    // Track consumer operations
})

Advanced Account Features

Account Trace Sampling

From server/accounts.go:113-115:
traceDest         string
traceDestSampling int
Configure message tracing per account:
  • Route trace messages to specific destination
  • Sample percentage of traced messages
  • Useful for debugging message flow

Account Tags

From server/accounts.go:106-107:
tags         jwt.TagList
nameTag      string
Tag accounts for organization and filtering:
{
  "tags": ["production", "tier-1", "region-us-west"]
}

External Authorization

From server/accounts.go:99:
extAuth      *jwt.ExternalAuthorization
Delegate authorization decisions to external services:
  • Server calls external service for auth decisions
  • Enables integration with existing auth systems
  • Supports custom authorization logic
  • Can use for publish/subscribe permission checks

Next Steps

Architecture Overview

Review overall NATS architecture

Clustering

Deploy accounts across clusters

Gateways

Share accounts across regions with gateways

Build docs developers (and LLMs) love