Skip to main content
The gateway now ships in the praisonai-bot package. praisonai serve gateway still works exactly as documented here; for a standalone install see praisonai-bot Migration.
Operator scopes grant teammates least-privilege access to a shared Gateway — read-only dashboards, send-but-not-approve operators, or full admins — without handing over the whole keys.
The user assigns scoped roles; each operator reaches only the gateway actions their role allows.

Quick Start

1

Single-operator (no scopes — unchanged)

Today’s setup keeps working. Authenticated clients receive all scopes when no policy is configured.
2

Multi-operator (scoped tokens)

Map each operator token to the scopes they need in gateway.yaml, then run your agent as usual.
When no auth_scopes policy is configured, every successfully authenticated client is granted all scopes — identical to today’s binary auth behaviour. Single-operator setups need no changes.

How It Works

  1. Client connects with a bearer token.
  2. Gateway resolves scopes via GatewayConfig.resolve_scopes(token).
  3. Each HTTP route and WebSocket action checks the required scope.
  4. Outbound events are filtered — approval events only reach clients with the approvals scope.

Scope Reference

admin implies every scope, but approvals and pairing do not imply each other — they are sibling capabilities. Only admin grants both. A method requiring both (via field escalation) therefore resolves to admin. See Incomparable scopes escalate to ADMIN.

Which scope should this operator have?


Configuration

YAML — flat mapping

Python


Scope-Gated Routes

For programmatic (WebSocket / RPC) methods, see Method → Scope Registry below. The WebSocket message requirement comes from the Method Scope Registry below — the dispatcher calls resolve_required_scope("message") (and resolve_required_scope("agent.message")) rather than hard-coding the check per route.

Method Scope Registry

New gateway methods are closed until classified — you cannot accidentally ship an unauthenticated control-plane call. Every method maps to a GatewayMethodDescriptor in the module-level GATEWAY_METHODS registry. resolve_required_scope looks up that descriptor and returns the effective scope for a call.
Default-deny. Unknown or unregistered methods require admin. Adding a new gateway method without calling register_gateway_method means any caller holding less than admin is denied — this is intentional (fail closed), so new control surface is never reachable by omission.

Quick lookup

Registering a plugin method

Plugin authors adding a new dispatcher method register its required scope once, at import time.
register_gateway_method refuses duplicates — pass replace=True to override an existing entry.

Per-field escalation

Escalation raises the required scope when a sensitive field is present; a plain call stays at the baseline.
Escalation only ever raises the requirement — a field mapped to a weaker scope than the baseline is ignored.

Strict fields (fail-closed on unknown payload)

strict_fields=True escalates any structural field not explicitly listed as safe, so unexpected payload keys fail closed.
APPROVALS and PAIRING are sibling scopes — neither implies the other. A method whose baseline is one but whose payload escalates to the other resolves to admin, its common upper bound, so a single-scope check can never be satisfied by holding only one of the two capabilities.

Core method classification

Core methods are classified at import; anything unlisted defaults to admin.
GatewayMethodDescriptor is a frozen dataclass; its escalate_fields and safe_fields collections are defensively copied at construction, so mutating the originals after registration cannot change resolution.

Method → Scope Registry

Every gateway method declares its required scope in one place — a declarative registry — instead of scattered checks per endpoint. New methods are closed until explicitly classified; an unregistered method requires admin.

Core method classification

Core methods are classified at import in praisonaiagents.gateway.protocols:

Registering a plugin method

A plugin that adds a new gateway surface registers its scope at import time:

Per-payload-field escalation (raise, never lower)

A descriptor can raise the required scope when a specific field appears in the params — an otherwise write method that mutates configuration should require admin when the config field is present:

Strict-fields mode (fail closed on unknown fields)

For high-risk methods, enable strict_fields=True with an allowlist of known-safe fields. Any field not in safe_fields or escalate_fields escalates to admin:

Incomparable scopes escalate to ADMIN

approvals and pairing are sibling capabilities — neither implies the other. When a method’s baseline is one and a field escalates to the other, the combined requirement escalates to admin rather than silently picking one (a single-scope check cannot satisfy both):

API reference

register_gateway_method is safe to call at plugin import time. The core-method classification runs at praisonaiagents.gateway.protocols import, so any plugin registration you do afterwards adds to the same registry.
Do not lower a scope by re-registering with replace=True unless you own the method. Downgrading the required scope of a core method is a security regression.
For the approval-flow context these scopes gate, see Scoped Approvals.

Common Patterns

Read-only dashboard viewer[read] for status and transcripts without send or approve rights. Send but not approve[read, write] for operators who reply to users but cannot resolve tool approvals. Approvals-only on-call[read, approvals] for security-sensitive approval resolution without channel admin rights. Full admin[admin] for SREs who need pause/resume/reconnect plus all other capabilities.

Error Handling

HTTP 403 when scope check fails:
WebSocket message without write scope:

Granting approvals is effectively remote command execution — never assign it casually. On a loopback-bound gateway, local non-proxied requests bypass auth by default and are granted all operator scopes — intended for local development only. External binds (0.0.0.0, LAN IPs) are unaffected and still require a token with the correct scopes. Set ALLOW_LOOPBACK_BYPASS=false to opt back into strict auth on loopback, or true to force-enable the bypass even on an external bind (unsafe — never do this in production). See Bind-Aware Auth.

Best Practices

Start every operator with [read] and expand only when their role requires it.
Issue separate tokens per operator so you can revoke one role without rotating everyone.
Combine approvals scope with /api/approval/allowlist for defence-in-depth on tool execution.
Prefer explicit scope lists over [admin] unless the operator truly needs channel control.
An unregistered gateway method defaults to admin (fail closed). When a plugin adds new surface, always call register_gateway_method(name, scope=...) at import time so the requirement matches the intent — not just whatever the current default happens to be.

Bind-Aware Auth

Token requirements when binding to external interfaces

Gateway Overview

Multi-channel gateway architecture and setup

Scoped Approvals

Resolve tool-execution approvals with the approvals scope