Munin
Munin developer portal
Get a key →
Guide · Concepts

Audiences, tokens, and what your agent can see.

Munin has one API surface, but two audiences look at it. An admin key sees everything in the workspace; an end-user token sees a sliver, scoped to one person. Picking the right credential is the difference between “the agent can do its job” and “the agent just leaked another customer’s order history.”

Two audiences admin · self_service

Every skill, MCP tool, REST endpoint, and KB document is tagged with one or both audiences. The audience that an incoming request resolves to comes from the credential it carries.

admin
The workspace operator. Can list every contact, edit every channel, mint keys, run back-office tools. Anything destructive or cross-tenant lives here.
self_service
A single end-user, acting on their own behalf through an agent. Can see their own conversations, place their own orders, read public KB articles. Cannot see anyone else’s data, even within the same org.

Three token kinds

The audience is implicit in the kind of credential the caller presents.

mn_admin_…
Long-lived workspace key. Stored server-side. Audience admin. This is what your backend uses when wiring up channels, importing KB articles, or running back-office MCP tools. Treat it like an AWS root key — never ship it to a browser.
mn_widget_…
Channel-bound public key for the chat widget. Audience self_service, plus channel-scoped origin allowlist and optional identity HMAC. Safe to embed in the page source: the key only authorizes calls to the one channel it was minted for, and only from origins on its allowlist.
mn_dlg_…
Short-lived delegated token (default TTL 30 min, max 24 h). Audience self_service by default. Minted server-side via POST /api/v1/tokens/delegated with an admin key, bound to a specific EndUser. The agent runtime carries this as bearer when it calls MCP tools on a customer’s behalf — voice calls, scheduled agents, anywhere outside the chat widget.

What scoping actually means

Audience is enforced at three layers — the controller picks the surface, RLS enforces tenancy, and the registry filters tool visibility:

1. Controller
The MCP controller resolves the actor’s audiences and exposes only matching tools. An admin key sees the full toolset; a delegated token sees the self_service subset. Same endpoint, different surface.
2. RLS
PostgreSQL row-level security uses the GUCs set by TenancyInterceptor (app.org_id, app.end_user_id) to filter every row read or written. A delegated token simply cannot select another end-user’s rows — the database refuses, regardless of what the code asks for.
3. KB & skill registry
Knowledge-base documents and skills carry their own audiences field. A public refund-policy article is tagged ['admin', 'self_service']; an internal escalation runbook is ['admin'] only. The agent search respects this filter without needing a separate query.

Picking the right one

Server-to-server admin tasks
Your backend wiring up Munin (creating channels, importing KB articles, monitoring health): mn_admin_*. One key per environment, rotate quarterly.
Chat widget on a public page
Embed mn_widget_* directly in the <script> tag. Add an origin allowlist on the channel, and identity HMAC if you want signed-in users to resume threads across devices.
Voice call / scheduled agent / custom UI
Your backend mints an mn_dlg_* bound to the specific EndUser, hands it to the agent runtime, and the agent calls MCP tools with it as bearer. The token dies on its own — no rotation, no cleanup.

Things to not do

Don’t ship admin keys to the browser
An mn_admin_* in client code is a workspace-wide compromise. If you find yourself reaching for one in a frontend, you probably want a delegated token instead.
Don’t use a long-lived delegated token
Delegated tokens are deliberately short-lived. If you need a session that lasts longer than 24 hours, mint a fresh token when the session resumes — the cost is one round-trip from your backend.
Don’t paper over audience with scopes
Scopes refine permissions within an audience. They don’t upgrade a self-service token into an admin one. If a tool isn’t visible to self_service, no scope value will reveal it.