Appearance
Access control & teams
In multi-tenant mode, org members are assigned roles, and operators can provision users automatically via SSO and SCIM. Backend automation uses management tokens. This page covers the role model, its current enforcement scope, and the provisioning flows.
Roles
merido defines five roles, ranked from least to most privileged:
| Role | What it's for |
|---|---|
| Viewer | Read-only — view usage. (Cannot read the audit log.) |
| Member | Make inference requests and view usage. |
| Billing | See spend, manage billing and budgets, export data. Cannot touch providers, keys, or members, and cannot make requests. (Orthogonal to the others.) |
| Admin | Day-to-day operations — manage members, providers, keys, teams, budgets, audit, guardrails, policy, SSO, and export data. Cannot transfer/delete the org or manage billing. |
| Owner | Full control, including org lifecycle and billing. |
Internally each role maps to a set of actions (ManageProviders, ManageKeys, ManageBudgets, ViewAudit, ManageGuardrails, ManageSso, ExportData, …). Every member can Proxy (make requests) except Billing and Viewer.
Enforcement scope
In multi-tenant mode the granular per-action role is enforced on the core control-plane resources: creating/updating/deleting/rotating keys (ManageKeys), adding/updating/deleting providers (ManageProviders), all budget mutations (ManageBudgets — Billing included), all virtual-model mutations (ManagePolicy), minting management tokens (admin), and reading the audit log (ViewAudit). A Member, Billing, or Viewer who attempts an action their role does not grant gets 403.
A few other admin surfaces (guardrails, routing policy, SSO, vault, settings) are still gated on org-admin status rather than a dedicated capability — equivalent for Owner/Admin vs everyone else, just coarser. The local single-user profile bypasses RBAC entirely (there is one user).
Management tokens
Management tokens (mdm_…) authenticate backend automation against the control plane (/api/*) without a browser session.
POST /api/management-tokens # create — returns the plaintext token ONCE
GET /api/management-tokens # list (metadata only)
DELETE /api/management-tokens/{id} # revokeA token carries a scope:
admin(default) — full control, can call mutating endpoints.readonly— only safe methods (GET/HEAD/OPTIONS); mutating calls are rejected403.
The plaintext is shown once at creation — only its hash is stored. Tokens can be created only from a logged-in session (not by another token), and revoked tokens are rejected immediately. Store them like any secret.
SSO (OIDC)
merido supports OIDC single sign-on so users log in through your identity provider:
GET /auth/oidc/login?org=<id> # begins auth-code + PKCE, redirects to the IdP
GET /auth/oidc/callback # completes the exchange, issues a merido sessionOn callback, merido finds-or-creates the user by their IdP subject and maps IdP groups to a merido role via a configurable group→role map. Configure the IdP per org:
GET /api/sso/config # current config (client secret shown only as a "set" flag)
PUT /api/sso/config # create/replace (the client secret is sealed at rest)
DELETE /api/sso/config # remove
POST /api/sso/test # OIDC discovery probe (SSRF-guarded)The OIDC flow state is carried in a sealed cookie so a callback can land on a different instance than the login began on.
SCIM provisioning
For automated user/group lifecycle, merido implements SCIM 2.0:
POST/GET/PUT/PATCH /scim/v2/Users # provision, fetch, replace, patch users
POST/PATCH /scim/v2/Groups # provision groups, add/remove membersSCIM callers authenticate with a dedicated bearer token (scim_…, created via the SSO settings), scoped to one org. Setting a user active = false deprovisions them: the user is locked out at session verify, their API keys are suspended, and their sessions are revoked.
Per-key limits
Every gateway key can carry its own guardrails, enforced by the gateway on each /v1 call:
| Limit | Effect when set |
|---|---|
| Allowed models | Only matching models may be requested; anything else is rejected. Globs: openai/*, *-mini, or an exact id. Empty = every model. |
| Requests / min | Per-key RPM cap, overriding the global MERIDO_RATE_LIMIT_RPM. |
| Tokens / min | Per-key TPM cap. Unset = no token-rate limit. |
| Session cap (USD) | Per-session spend ceiling for this key. |
Set them in the dashboard under Access Keys → Gateway keys → Create a key → Limits, or change them on a live key from the Edit limits action in the key's row (also reachable by clicking the limit chips under the key's name).
Through the API:
bash
# create
curl -X POST https://your-gateway/api/keys \
-H "Authorization: Bearer $MERIDO_MGMT_TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"team-a","scope":"proxy","allowed_models":["openai/*"],
"rate_limit_rpm":600,"rate_limit_tpm":2000000}'
# retune later — omitted fields keep their current value
curl -X PATCH https://your-gateway/api/keys/12 \
-H "Authorization: Bearer $MERIDO_MGMT_TOKEN" -H 'Content-Type: application/json' \
-d '{"rate_limit_rpm":900}'PATCH merges: a field you omit is left untouched (including cost_center), [] clears the allow-list, and 0 clears a cap. Rotating a key carries its limits over to the new secret.
Credential lifecycle
A gateway key or management token is in exactly one of four states:
| Status | How it gets there | Reversible |
|---|---|---|
| Active | The normal state — it authenticates. | — |
| Expired | Its TTL lapsed (ttl_seconds at creation). | No — rotate it to get a working replacement that inherits its name, scope, cost center and limits. |
| Revoked | DELETE /api/keys/{id} (dashboard: Revoke key). | No. |
| Disabled | The service account that owns the key was disabled. | Yes — re-enable the service account. |
Revoking is a soft delete: the row is disabled and stamped revoked_at, so it stays in GET /api/keys as an auditable tombstone rather than vanishing. Rotation is the exception — it hard-deletes the old row after the replacement exists, so rotating does not accumulate tombstones.
Because the list therefore contains dead credentials, the dashboard's Access Keys page shows only Active ones by default. A Show: Active / Inactive / All filter appears above the table as soon as anything is revoked, expired or disabled, and searching while filtered tells you how many matches are being held back. Dead rows carry no actions — the one exception is Rotate on an expired key, which is how you renew it.
Related
- Multi-tenancy — enabling orgs, signup, and tenant isolation.
- Audit log & SIEM export — every role, SSO, and SCIM change is audited.
- Credential policy, vault & proxy pools — securing each org's credentials.