natsauth

package
v0.17.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 3, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package natsauth implements Auth V2 Phase 3: decentralized NATS auth via per-Account JWTs (the "NSC model" — see docs/AUTH-V2.md §Phase 3).

At runtime ppz-server holds a single Account signing key. On /auth/exchange it generates a fresh user nkey pair, mints a User JWT with subject permissions scoped to the caller's org, and hands (jwt, seed) back to the daemon. NATS validates the chain locally — no callback to ppz-server in the data path.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MintAccountJWT

func MintAccountJWT(operatorKP nkeys.KeyPair, orgName string, accountKP, signingKP nkeys.KeyPair) (string, error)

MintAccountJWT signs a fresh Account JWT for orgName, with the supplied signing-key public registered as an authorized signer. The Operator key (`operatorKP`) signs the JWT — caller is responsible for that key's security (production: env var).

JetStream limits are set to unlimited (-1) — a single ppz-server is the only client of every account anyway, so per-account quotas don't add safety, only friction.

func MintUserJWTInAccount

func MintUserJWTInAccount(accountPub string, signingKP nkeys.KeyPair, name string, pubAllow, subAllow []string, expUnix int64) (jwtStr, seed string, err error)

MintUserJWTInAccount mints a User JWT in the supplied account, signed by that account's signing key. Decoupled from `Account` so callers that hold (account_pub, signing_kp) directly — like per-org account loaders in Phase 3.5 — can mint without constructing an Account struct.

expUnix is the JWT's `exp` claim (seconds since epoch). The `nbf` claim is set 30s before now to absorb clock skew.

func StartEmbeddedNATSWithAuth

func StartEmbeddedNATSWithAuth(cfg EmbeddedConfig) (*natsserver.Server, error)

StartEmbeddedNATSWithAuth boots an embedded nats-server with decentralized auth: the supplied operatorJWT is set as the trusted operator, and the account JWTs are preloaded into the in-memory resolver. JetStream + auth requires a system account.

Returns the running server. Caller is responsible for Shutdown().

Types

type Account

type Account struct {
	AccountPub string        // public nkey of the Account
	SigningKey nkeys.KeyPair // derived from PPZ_NATS_ACCOUNT_SIGNING_SEED; held in memory only
	AccountJWT string        // signed by Operator; loaded into the embedded NATS resolver at boot
}

Account is the runtime state ppz-server needs to mint User JWTs. Loaded once at boot from environment via LoadAccountFromEnv.

func LoadAccountFromEnv

func LoadAccountFromEnv() (*Account, error)

LoadAccountFromEnv reads the Account credentials from process env vars (PPZ_NATS_ACCOUNT_JWT, PPZ_NATS_ACCOUNT_SIGNING_SEED). Fails fast at boot if either is missing or malformed.

func (*Account) MintServerUserJWT

func (a *Account) MintServerUserJWT(expiry time.Duration) (jwtStr, seed string, err error)

MintServerUserJWT mints a User JWT with broad pub/sub permissions in this Account. ppz-server uses this to authenticate its own in-process NATS connection (which manages JetStream streams across every org) — no cross-org isolation needed.

func (*Account) MintUserJWT

func (a *Account) MintUserJWT(orgID string, expiry time.Duration) (jwtStr, seed string, err error)

MintUserJWT generates a fresh user nkey pair, signs a short-lived User JWT (with the subject scope for orgID embedded), and returns (jwt, seed) for handing to a daemon over /auth/exchange. The seed is the user's own private key — ppz-server keeps no copy.

type EmbeddedConfig

type EmbeddedConfig struct {
	Host             string // "" → 127.0.0.1
	Port             int    // 0 → OS picks
	OperatorJWT      string
	AccountJWT       string
	SystemAccountJWT string // optional — required for JetStream
	JetStream        bool   // false → JS disabled (auth-only mode, used by tests)
}

EmbeddedConfig groups the config for StartEmbeddedNATSWithAuth. All JWT fields are required; SystemAccountJWT enables JetStream.

type Subjects

type Subjects struct {
	Publish   []string
	Subscribe []string
	Deny      []string
}

Subjects describes the NATS subject scope embedded in a User JWT.

func SubjectsForOrgUser

func SubjectsForOrgUser(orgID string) Subjects

SubjectsForOrgUser returns the standard ppz subject scope for a user in orgID. The org_id is the lowercase-hyphenated UUID, used as the subject root (matches natsubj.SubjectFor).

pub: <orgID>.>      — own data-plane subjects
     _INBOX.>       — reply subjects for NATS request/reply
     $JS.API.>      — JetStream API (stream/consumer mgmt)
sub: <orgID>.>      — own data-plane subjects
     _INBOX.>       — receive replies

Known limitation: $JS.API.> isn't subject-pattern scopable per-org (stream names occupy a single subject token, so wildcards can't constrain the prefix). All orgs share the same JetStream API surface. Data-plane isolation (the load-bearing case for broadcasts) IS enforced via the <orgID>.> scope. Per-org account isolation is the proper fix; tracked in V3+ out-of-scope.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL