Overview
The Users page turns theuser_path hierarchy
behind your API keys into a tree of groups and users, and lets each node
restrict which models requests under it may call:
/acmeand/acme/engare groups — they contain other paths./acme/eng/aliceis a user — API keys are bound directly to it.
Rules
- New keys and nodes allow everything. A node or key with no
allowed_modelsimposes no restriction of its own. - Listing models restricts. Once a node lists models, requests under it may only use models matching that list.
- Lists intersect down the tree. A request must satisfy the allowlist of
its API key, of its user path, and of every ancestor up to
/. A child can narrow what its group allows but never widen it. - Model-side rules still apply. A virtual model access policy that hides a model from a subtree keeps hiding it.
GET /v1/models returns only the models the caller may use, so clients see
the same picture the gateway enforces.
Requests authenticated by other means follow the same path rules: an
OIDC SSO session or a request carrying only the
user-path header is limited by the policies on its user_path; only managed
API keys additionally carry a per-key allowlist. The master key has no bound
user path: without the header it is unrestricted, with the header it is
scoped like any other request on that path.
How access is resolved
Policies hang off the user-path tree and are combined top-down. Every list on the way from the root to the request’s path must match, and the API key’s own list is applied last: For one request the gateway checks, in order: Where the pieces come from:
A node without a list contributes nothing to the chain; it neither widens nor
narrows. This is why a new key or a fresh group starts with access to
everything, and why
/acme/sales above still sees both providers.
Selectors
Each entry in an allowlist is one selector:
Provider names must match a configured provider; unknown names are rejected
when the policy is saved. Virtual model aliases resolve to their target before
the check runs, so allow the target model, not the alias.
Example
An API key bound to
/acme/eng/alice with its own
allowed_models: [anthropic/claude-sonnet-4-6] narrows Alice further to that
single model.
A denied request receives 400 with code model_access_denied.
Managing policies
Dashboard
Users lists every node with its own allowlist, its effective models —
the path-level result once its own list, every parent’s list, and the
model-side virtual-model policies are applied (a red None flags a node
whose lists intersect to nothing) — and how many API keys are bound to it. A
managed API key’s own allowed_models can narrow a request further than the
path shows. The editor warns while you type when the
list would leave no model available. Add or edit a node to
set its models; remove the policy to fall back to the parents’ limits.
The key count links to the API Keys page filtered to that path’s subtree,
and each row has an Add API key action that opens the create-key form with
the path prefilled.
Per-key allowlists live on the API Keys page: set Allowed models when
creating a key or edit them later from the key’s row. Its Effective models
column is the final answer for that credential — path policies, the key’s own
list, and model-side policies combined.
Configuration
Declare policies inconfig.yaml under users: (see the example above) or
in the USERS environment variable as a JSON array with the same fields:
Admin API
POST /admin/auth-keys accepts allowed_models at creation time. See
Admin Endpoints for request and response shapes.