auth.yaml file configures authentication and access control for the Hivenet Router HTTP APIs.
It controls two separate surfaces:
apiprotects client-facing/v1/*endpointsadminprotects operator-facing/admin/*endpoints
Load the file
Pass the path when starting the router:admin.mode: none unless:
Top-level structure
Mode combinations
Dynamic API mode requires:
/admin/api-keys/* controls the client-key registry.
Minimal static configuration
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
- the raw client key
- its SHA-256 hash
- a masked preview
- a ready-to-paste YAML entry
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
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
Theowner value becomes the tenant ID used by Hivenet Router.
- quota buckets
- request metrics
- token metrics
- audit records
- tenant dashboards
Creation date
DD-MM-YYYY keeps it consistent with generated entries and static expiration dates.
Expiration date
Dynamic API-key entries use RFC 3339 timestamps instead. That format belongs to the administration API, not static
auth.yaml entries.Model allowlist
Usemodels to restrict a flat-quota key to exact model names:
- is hidden from
GET /v1/models - returns
404fromGET /v1/models/{model} - returns
403 model_forbiddenfor an inference request
Precedence with per-model quotas
Whenquota.per_model is present, its model names become the effective allowlist.
For example:
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:
Request-rate behavior
requests_per_minute uses a continuously refilling token bucket.
- can initially hold up to one minute’s configured capacity
- deducts one unit for each admitted request
- refills continuously at the configured rate
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
- 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
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 usesmode: 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.
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.
Cross-config validation
The router validates these invariants at startup, on SIGHUP reload of auth or policy files, and on dynamicPUT /admin/api-keys/{id} and POST /admin/api-keys/replace writes:
max_occupancy_sharemust be0(unset) or in(0, 1].- Input and output token-per-minute values cannot be negative.
- For every serverless model the key can reach, a nonzero
input_tokens_per_minutemust be at least the policy’smax_input_tokens.
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
Usequota.per_model when models need different limits.
Strict enumeration
Every model the key may call must appear inper_model.
There is:
- no wildcard
- no fallback entry
- no implicit unlimited model
429:
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:
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.
Do not mix quota shapes
This is invalid:- flat quotas
- per-model quotas
Empty and partial entries
This is invalid:0 when one field should be unlimited.
Token-budget enforcement
Hivenet Router checks a chat request in two stages.Before forwarding
The router estimates:max_completion_tokens, when provided- otherwise
max_tokens - otherwise no requested output reservation
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/*.
Administrator keys are not stored in
auth.yaml.
Provide them as raw, comma-separated values:
Dynamic mode auto-elevation
This configuration:Complete static example
Complete dynamic example
The file can select dynamic mode without containing client keys:File permissions
The router process must be able to read the file, while other users should not. For a service running ashivenet-router:
- tenant names
- model access
- quotas
- expiration dates
- key previews
- operational structure
Hot reload
After editing the file, sendSIGHUP:
- reads and parses the updated file
- validates every provider and static key
- builds replacement API and admin providers
- swaps them atomically
- resets in-memory quota limiter state
- republishes configured tenant quota metrics
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
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:
Administrator key values always come from:
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-keymode 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_shareoutside(0, 1]when set- a serverless key whose nonzero
input_tokens_per_minuteis below the policymax_input_tokens - an empty
per_modelmap - an empty model name in
per_model - a per-model entry missing one quota field
- negative per-model quota values
- admin mode
api-keywithoutHIVENET_ROUTER_ADMIN_API_KEYS - admin mode
nonewithoutHIVENET_ROUTER_ALLOW_INSECURE_ADMIN=true - duplicate administrator keys
Troubleshooting
The router says the key list is empty
When using:A static key always returns 401
Check that:
- the application sends the raw key rather than its hash
key_hashwas 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
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:
The router rejects an expiration date
Static dates must use: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: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.

