Skip to main content
The auth.yaml file configures authentication and access control for the Hivenet Router HTTP APIs. It controls two separate surfaces:
  • api protects client-facing /v1/* endpoints
  • admin protects operator-facing /admin/* endpoints
Agent authentication does not use this file. Router-agent trust uses the shared JWT secret configured separately on the router and agents.

Load the file

Pass the path when starting the router:
The environment-variable equivalent is:
When no file and no client authentication mode are configured, the client API defaults to:
The administration surface is secure by default. The router refuses to start with admin.mode: none unless:
The insecure administrator override exposes every /admin/* endpoint to any network client that can reach the router. Use it only in an isolated development environment.

Top-level structure

The complete shape is:

Mode combinations

Dynamic API mode requires:
The router refuses to start without an administrator key because /admin/api-keys/* controls the client-key registry.

Minimal static configuration

Provide administrator keys separately:
The raw client key is not stored in the YAML file. Only its SHA-256 hash is stored.

api section

The api section controls /v1/*.

api.mode

Accepted values are: When mode is api-key, keys must contain at least one valid entry. When mode is dynamic, do not define the runtime key registry in auth.yaml. An external service populates it through the administration API.

api.keys

Each item under keys defines one static client credential:

Static key fields

key_hash

Generate the key and hash with:
The command prints:
  • the raw client key
  • its SHA-256 hash
  • a masked preview
  • a ready-to-paste YAML entry
Store the raw key in a secret manager. Put only the hash in auth.yaml. Duplicate key_hash values are rejected when the file loads. Use the exact lowercase SHA-256 output produced by hivenet-router keygen or sha256sum.

key_preview

This field is optional and informational. It can help identify the credential in static configuration and selected operational logs or displays. The dedicated audit record does not include a key_preview field. Static-key audit records normally have an empty key_id, while dynamic-key audit records use the registry entry ID. The preview is never used to authenticate a request.

metadata

name and owner must not be empty.

Owner identity

The owner value becomes the tenant ID used by Hivenet Router.
It labels and groups:
  • quota buckets
  • request metrics
  • token metrics
  • audit records
  • tenant dashboards
Keys with the same owner share quota state.
Give keys the same owner only when they belong to the same tenant and should share quota buckets.When several keys share an owner, keep their quota configuration consistent. Different limits attached to the same shared bucket can produce confusing behavior.

Creation date

This field is informational. The current loader does not use it for authentication or validate its format. Using DD-MM-YYYY keeps it consistent with generated entries and static expiration dates.

Expiration date

The format must be:
The key remains valid through the complete named day in UTC. For:
the key becomes invalid at:
An empty or omitted value means the key does not expire. Invalid dates prevent the configuration from loading.
Dynamic API-key entries use RFC 3339 timestamps instead. That format belongs to the administration API, not static auth.yaml entries.

Model allowlist

Use models to restrict a flat-quota key to exact model names:
An empty or omitted list means unrestricted model access:
Model names are exact and case-sensitive. A model outside this list:
  • is hidden from GET /v1/models
  • returns 404 from GET /v1/models/{model}
  • returns 403 model_forbidden for an inference request

Precedence with per-model quotas

When quota.per_model is present, its model names become the effective allowlist. For example:
The key can use only:
The models list is ignored for access decisions. This gives per-model quota configuration one source of truth for both access and limits.

Flat quotas

The flat quota shape applies one shared budget to every model the owner may call.
The two per-minute token fields are available only in the flat quota shape. They cannot be combined with quota.per_model, and negative values are rejected. Flat quota buckets are associated with the owner rather than the individual key. For example, two credentials with:
share the same request and token counters.

Request-rate behavior

requests_per_minute uses a continuously refilling token bucket.
does not mean the counter resets at the start of every wall-clock minute. By default, the bucket:
  • can initially hold up to one minute’s configured capacity
  • deducts one unit for each admitted request
  • refills continuously at the configured rate
A value of 0 disables the request-rate limit. Set HIVENET_ROUTER_RPM_BURST_SECONDS to a value from 1 through 59 to reduce the initial and maximum burst to that many seconds of the effective rate. The capacity is floor(RPM × seconds / 60), with a minimum of 1. The default 0 keeps the full-minute burst. This setting applies to flat RPM and to the live replica-scaled RPM of quota.per_model entries.

Daily token behavior

The daily budget:
  • applies to language-model chat traffic
  • combines input and output tokens
  • resets at midnight UTC
  • is shared by models and keys using the same flat owner bucket
A value of 0 disables the token budget. Embedding and reranking requests currently participate in request-rate limits but do not charge input against tokens_per_day.

Serverless per-key caps

When the effective policy uses mode: serverless, the flat quota shape and key entry accept:
max_occupancy_share sits on the key entry rather than inside quota because it is a fraction of pool capacity rather than a rate. The runtime behavior is:
  • Input tokens per minute (ITPM) uses a continuously refilling, one-minute-capacity bucket. The same learned estimate used by B1 and occupancy is deducted before the daily budget, so an ITPM rejection does not spend daily tokens. Cached prompt prefixes currently count in full.
  • Output tokens per minute (OTPM) is charged from exact completion usage after a local response. Output is not reserved. If recent output drains the bucket, the next request returns 429 rate_limit_exceeded. One response can drain at most one minute of capacity.
  • Occupancy share limits the key’s simultaneous token-weighted footprint to:
    The per-key fairness controller intentionally does not apply HIVENET_ROUTER_ADMIT_FRACTION. The global B2 controller still applies that fraction and remains the safety limit for the pool.
These limits do not run for mode: reserved, and 0 disables each limit. Their shares may be deliberately oversubscribed and do not need to add up to 1. B4 rejections set Retry-After: 1; the ordinary request-per-minute limiter uses the same rate_limit_exceeded code without that header. Provider fallback retains the pre-routing ITPM charge but does not charge provider output to OTPM.
Dynamic keys are isolated by their registry key ID. Static-key authentication currently leaves that ID empty, so the handler’s anonymous fallback makes the serverless token-rate buckets and occupancy controller shared across static keys for the same model. Treat this as a current implementation limitation when choosing static or dynamic authentication.

Cross-config validation

The router validates these invariants at startup, on SIGHUP reload of auth or policy files, and on dynamic PUT /admin/api-keys/{id} and POST /admin/api-keys/replace writes:
  1. max_occupancy_share must be 0 (unset) or in (0, 1].
  2. Input and output token-per-minute values cannot be negative.
  3. For every serverless model the key can reach, a nonzero input_tokens_per_minute must be at least the policy’s max_input_tokens.
An invalid dynamic write returns HTTP 400. An invalid reload leaves the previous valid auth and policy configuration active. The repository’s auth.DeriveKeyDefaults helper calculates suggested B4 values from certified model limits. The router does not load router_limits.yaml or call that helper while loading auth.yaml; provisioning tooling must write the derived values into each key entry.

Per-model quotas

Use quota.per_model when models need different limits.
Each model entry requires both fields.

Strict enumeration

Every model the key may call must appear in per_model. There is:
  • no wildcard
  • no fallback entry
  • no implicit unlimited model
A request for an unlisted model is rejected with HTTP 429:
Model discovery hides unlisted models, and model detail returns 404.
This differs from the explicit models allowlist.An explicit allowlist violation returns 403 model_forbidden for inference. An unlisted quota.per_model request is rejected earlier by quota admission with 429 rate_limit_exceeded.

Per-replica request limit

The effective request limit is:
For:
When no healthy replica exists, Hivenet Router skips the quota check so routing can return the more accurate availability error. The token budget does not scale with replicas.
remains three million tokens regardless of fleet size.

Do not mix quota shapes

This is invalid:
Choose one shape:
  • flat quotas
  • per-model quotas
The loader rejects a key that contains both.

Empty and partial entries

This is invalid:
This is also invalid:
Every entry must explicitly include:
Use 0 when one field should be unlimited.

Token-budget enforcement

Hivenet Router checks a chat request in two stages.

Before forwarding

The router estimates:
It uses:
  1. max_completion_tokens, when provided
  2. otherwise max_tokens
  3. otherwise no requested output reservation
The worst-case total must fit inside the remaining daily budget. This first check does not deduct the requested maximum output. It only verifies that the request could fit. After admission, Hivenet Router charges the estimated input tokens.

After the response

Hivenet Router charges the actual completion tokens after the backend responds. For non-streaming responses, it uses backend usage data when available and estimates missing values when needed. For streaming responses, accounting happens after the stream finishes. The client may already have received output before final usage is known, so an over-budget stream cannot be withdrawn.

Multimodal limitation

Post-response usage from a compatible backend can include image and audio token costs accurately. The pre-request estimate is primarily text based. Image and audio content may therefore be underestimated at admission. Treat token budgets as approximate admission control for multimodal requests until model-aware preflight estimation is implemented.

admin section

The admin section controls /admin/*.
Accepted values are: Administrator keys are not stored in auth.yaml. Provide them as raw, comma-separated values:
Send one as a bearer token:
Hivenet Router hashes the raw values when the router starts. It does not retain their plaintext form in the provider. Duplicate administrator keys are rejected.

Dynamic mode auto-elevation

This configuration:
is treated as:
The router then requires:
This protection cannot be disabled while dynamic client-key management is active.

Complete static example

Set administrator keys separately:

Complete dynamic example

The file can select dynamic mode without containing client keys:
Set the administrator credential:
Start the router:
Then populate the in-memory client registry through:
Dynamic entries are not persisted by this file and must be restored after a router restart.

File permissions

The router process must be able to read the file, while other users should not. For a service running as hivenet-router:
A process running under your own user account can use:
The file contains hashes rather than raw client keys, but it still exposes:
  • tenant names
  • model access
  • quotas
  • expiration dates
  • key previews
  • operational structure
Include it only in encrypted backups.

Hot reload

After editing the file, send SIGHUP:
For Docker Compose:
Hivenet Router:
  1. reads and parses the updated file
  2. validates every provider and static key
  3. builds replacement API and admin providers
  4. swaps them atomically
  5. resets in-memory quota limiter state
  6. republishes configured tenant quota metrics
Reloading authentication rebuilds in-memory quota state. Request-rate buckets reset. Daily token usage also resets with the memory backend; the badger backend preserves and restores daily token state.
In-flight requests continue using the provider they already reached. If parsing or validation fails, the previous providers remain active.

Dynamic-mode reload

When the router already uses dynamic client authentication:
  • the dynamic client registry is preserved
  • the administration provider is reloaded
  • switching to static or no-auth mode is rejected
Changing between static and dynamic client authentication requires a router restart.
SIGHUP rebuilds administrator authentication from the current process environment.Editing a systemd EnvironmentFile does not change the environment of an already running process. Restart the router after changing HIVENET_ROUTER_ADMIN_API_KEYS.

Configuration precedence

When --auth-config-file is set, the file controls the API mode. The environment variable:
is used only when no auth file is configured. Administrator key values always come from:
when admin mode is api-key.

Validation failures

The router rejects the configuration at startup or reload when it finds issues such as:
  • unknown API or admin modes
  • api-key mode with an empty key list
  • an empty key_hash
  • duplicate static key hashes
  • an empty metadata name
  • an empty metadata owner
  • an invalid static expiration date
  • mixed flat and per-model quota shapes
  • negative input or output token-per-minute values
  • max_occupancy_share outside (0, 1] when set
  • a serverless key whose nonzero input_tokens_per_minute is below the policy max_input_tokens
  • an empty per_model map
  • an empty model name in per_model
  • a per-model entry missing one quota field
  • negative per-model quota values
  • admin mode api-key without HIVENET_ROUTER_ADMIN_API_KEYS
  • admin mode none without HIVENET_ROUTER_ALLOW_INSECURE_ADMIN=true
  • duplicate administrator keys
On startup, a validation error stops the router. During SIGHUP reload, a validation error leaves the previous authentication providers active.

Troubleshooting

The router says the key list is empty

When using:
define at least one item under:
For dynamic mode, use:
instead.

A static key always returns 401

Check that:
  • the application sends the raw key rather than its hash
  • key_hash was generated from the exact raw value
  • the key has not expired
  • the updated file loaded successfully
  • the request reaches the intended router
  • the authorization header is preserved by proxies
Generate a fresh key rather than editing hashes manually.

A key receives 403 model_forbidden

The key uses the explicit models allowlist and the requested model is absent. Check exact spelling and capitalization.

A per-model key receives 429

Read the error message. When it says:
add an exact entry under:
or use a flat quota shape instead.

The router rejects an expiration date

Static dates must use:
Valid:
Invalid:

SIGHUP does not apply the new mode

Changing between static and dynamic authentication requires a router restart. SIGHUP supports changes within the current mode, such as:
  • adding or revoking static keys
  • changing model restrictions
  • changing quotas
  • changing static expirations
  • rebuilding administrator keys from the current environment

Administration endpoints remain open

Set:
and provide:
Then restart the router if you changed its process environment.

Next steps

Model restrictions

Design model access and discovery boundaries for applications and tenants.

Key rotation

Rotate static, dynamic, administrator, agent, and provider credentials.

Audit logging

Record authenticated owners, key identifiers, models, and request outcomes.