Skip to main content

Overview

The Users page turns the user_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:
  • /acme and /acme/eng are groups — they contain other paths.
  • /acme/eng/alice is a user — API keys are bound directly to it.
Nothing needs to be created up front. The tree is derived from the user paths of existing API keys; add a policy to a node only when you want to restrict it.

Rules

  1. New keys and nodes allow everything. A node or key with no allowed_models imposes no restriction of its own.
  2. Listing models restricts. Once a node lists models, requests under it may only use models matching that list.
  3. 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.
  4. 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 in config.yaml under users: (see the example above) or in the USERS environment variable as a JSON array with the same fields:
Declared policies shadow dashboard rows for the same path and are read-only in the dashboard. A misspelled provider in a declared policy fails startup.

Admin API

POST /admin/auth-keys accepts allowed_models at creation time. See Admin Endpoints for request and response shapes.
Last modified on August 30, 2026