Users, roles & SSO
Yagra ships with role-based access control from the first release: every account — local, SSO-provisioned, or an API token — carries one of three roles, every state-changing action is permission-checked, and everything that changes state lands in an audit log. This page covers the whole access-control surface: roles and permissions, local accounts and their session lifecycle, single sign-on, API tokens, and how the public-dashboard mode interacts with all of it.
Three roles, in strictly increasing order of privilege — each role holds everything the one below it holds:
- Viewer — read-only: inventory, metrics, dashboards, topology, events, and alerts. A Viewer can look at everything the WebUI shows and change nothing.
- Operator — Viewer plus incident response: acknowledge or mute alerts, run Troubleshoot analyses and AI root-cause explanations, and open or close maintenance windows. This is the on-call role.
- Admin — full control: monitoring configuration, credentials, user management, and the audit log.
The WebUI shows the full role-versus-privilege matrix under Settings ▸ Roles & privileges.
One recent change worth knowing if you assigned roles under an earlier release: running
a Troubleshoot analysis is now an Operator action. It used to require Admin over the
REST API (while, inconsistently, a Viewer token could launch the same analysis over MCP);
both surfaces now ask for the same incident-response permission that acknowledging an
alert takes. An analysis reads monitoring history and changes no configuration, so it
belongs to the on-call operator. Reading past runs and their findings is unchanged and
still open to Viewers — but a Viewer-scoped API token can no longer launch analyses
over /mcp.
Permissions & group scoping
Section titled “Permissions & group scoping”Roles are bundles of permissions. The full set:
| Permission | What it allows | Viewer | Operator | Admin |
|---|---|---|---|---|
| View | View inventory, metrics, and alerts | ✔ | ✔ | ✔ |
| Respond to incidents | Acknowledge or mute alerts, run Troubleshoot analyses, request AI root-cause explanations | ✔ | ✔ | |
| Manage maintenance | Open or close maintenance windows | ✔ | ✔ | |
| Manage configuration | Create and edit nodes, profiles, thresholds, and collection | ✔ | ||
| Manage credentials | Create, edit, and rotate monitoring credentials | ✔ | ||
| Manage users | Manage user accounts and role assignments | ✔ | ||
| View audit | Read the audit log (who changed what) | ✔ |
Permissions attach to roles, not to individual accounts — you choose one of the three roles per account, and the matrix above decides the rest.
Group scoping. Alongside its role, an account carries a visibility scope: all groups, or a named set of node groups. The scope declares which slice of the inventory the account is about — a node that belongs to no group at all falls only under the all-groups scope.
The API’s read endpoints do filter by the caller’s group scope: node lists narrow to
the allowed groups and everything beneath them, aggregates and rankings are filtered to
the same set, and a node outside the scope answers 404 — the same answer an unknown id
gets, so the id space cannot be probed. A few endpoints have no per-node attribution left
to filter (a rendered report, a pre-summed fleet timeline); those refuse a
group-scoped caller rather than quietly serving fleet-wide numbers.
Assigning a scope. Under Settings ▸ Users, the row action Change scope limits an account to the groups you tick; leaving all of them unticked restores fleet-wide visibility. Accounts start unrestricted — including SSO accounts, which are provisioned on first sign-in and narrowed here afterwards. The assignment survives every subsequent login: it is a Yagra-side decision, not something re-derived from your directory.
Two rules are worth knowing before you use it:
- An Admin cannot be scoped. Administration is fleet-wide — an admin can reconfigure any node — so a narrowed admin would read an inventory that hides nodes it can still edit. Promoting an account to Admin clears whatever scope it held.
- A scope naming no groups is refused, rather than stored. It would otherwise be an account that signs in successfully to an empty inventory with nothing on screen to explain why.
Saving a scope signs the account out of its current sessions, the way a role change does: the scope is captured in the session token, so a live one would keep the old, wider view.
The account menu says so when the account you are signed in as is limited — a scoped operator’s lists are simply shorter, with nothing else to distinguish “you can see three sites” from “there are three sites”.
Local accounts
Section titled “Local accounts”A fresh install bootstraps one local account, admin, and prints its initial password
once in the core logs on first start:
docker compose logs core # look for the one-time admin passwordSign in with it, then change it. Local accounts are managed under Settings ▸ Users: create accounts with a role, change or reset passwords (“Change password”), disable an account, or delete it.
Session lifecycle. Logging in issues a bearer session token, which the WebUI holds for you. Sessions are hardened in the ways you would expect of a system that pages people:
- Sessions expire — after an idle period and after an absolute lifetime, whichever comes first. Logging out revokes the token server-side immediately.
- Admin actions cut sessions off at once: disabling an account, demoting its role, resetting its password, or deleting it invalidates that account’s active sessions on the spot — an already-issued token does not linger.
- The login endpoint applies brute-force protection: a per-account exponential lockout after repeated failures, plus a global attempt-rate cap, so password-guessing runs are throttled rather than serviced.
In a high-availability deployment with a shared session signing key, a login is accepted by every core and survives a core restart or failover — and a logout, disable, role change, or password reset takes effect across all cores right away.
Single sign-on
Section titled “Single sign-on”Yagra signs users in against an external identity provider over OpenID Connect — Google Workspace, Microsoft Entra, Okta, Keycloak, or any other OIDC-capable IdP — alongside local accounts, not instead of them.
Configure a provider under Settings ▸ Authentication. Start by picking which identity provider it is — Microsoft Entra ID, Okta, Google Workspace, or “Other” for any other OIDC provider — and the form then asks only for what that product actually needs, rather than presenting eight free-text fields and assuming you already know what your IdP wants:
- Entra ID asks for the directory (tenant) ID and builds the issuer URL from it. It requests only
the standard OIDC scopes, because Entra rejects any non-standard scope outright — a generic form
that pre-filled
groupsnever reached a sign-in page at all. Enable the groups claim in the app registration’s token configuration; it arrives as group object IDs. - Okta asks for the org domain and builds the issuer URL from it, requesting the
groupsscope its org authorization server serves. A custom authorization server has a different issuer and belongs under “Other”. - Google Workspace has one issuer, so there is no URL to enter — and it has no group→role mapping, deliberately: Google does not put group membership in the ID token, so a mapping configured against it could never match. A default role is required instead, since without one every sign-in would be denied.
- Other asks for the full set directly: issuer URL, client ID and client secret from your IdP’s app registration, plus the redirect URL Yagra should be called back on and the scopes to request.
Except on Google Workspace, a provider carries a mapping from IdP groups to Yagra roles, so membership in your directory decides whether someone lands as Viewer, Operator, or Admin.
Accounts are provisioned just in time: the first successful SSO sign-in creates the Yagra account, and the account’s role follows the IdP’s group mapping on every login — move someone between directory groups and their Yagra role updates the next time they sign in. Once a provider is enabled, a “Continue with SSO” button appears on the login screen.
The client secret is envelope-encrypted at rest and never shown again after it is saved — the same treatment Yagra gives monitoring credentials.
LDAP / Active Directory
Section titled “LDAP / Active Directory”For directories that are not OIDC providers, Yagra signs people in against LDAP or Active Directory directly. Configure it at Settings ▸ Auth ▸ Directory (LDAP/AD). There is no second button and no separate URL: people use the ordinary login form with their corporate credentials.
Yagra searches for the person with a service account and then re-binds as the entry it found, so no DN pattern has to be guessed for your directory’s layout. Group membership maps to a Yagra role through the same mapping the SSO provider uses, matching a group by its full DN or just its name, and an account is created on first successful sign-in.
- Local accounts are always tried first. A directory that is unreachable can never lock an administrator out — keep one local admin and a rollback stays survivable.
- LDAPS and StartTLS only, with a field for your private CA. There is deliberately no way to skip certificate verification.
- The bind password is envelope-encrypted at rest, like every other secret.
- A Test button reports each stage separately and, given a username, shows the DN, the groups, and the role that person would receive — including when the answer is “denied”, which the login form otherwise reports as an ordinary wrong password.
An API token owned by a directory account expires with its owner’s silence, the same way an
SSO-owned one does (YAGRA_PAT_OIDC_IDLE_DAYS) — a directory disabling somebody is not something
Yagra is told about, so the owner going quiet is the only signal there is.
SAML is answered with a bridge rather than an implementation: put Keycloak or Dex in front as a SAML→OIDC bridge. Yagra does not verify XML signatures itself.
API tokens
Section titled “API tokens”For unattended clients — an MCP-connected AI assistant, a script, a CI job — Yagra issues
long-lived personal access tokens with a yat_ prefix. An admin mints them under
Settings ▸ API tokens; the raw token value is shown exactly once at creation, and
only its hash is stored.
A token is defined by five things:
- Surfaces. Which of the MCP endpoint and the
REST API it may authenticate. A token created before this field existed
carries
mcpalone, so upgrading never widens an existing credential; granting REST is an explicit choice at creation. - An owner. The account the token acts as. A token can never exceed its owner in either dimension: its effective role is the lower of the token’s role and the owner’s current role, and its scope is capped at the owner’s the same way — so demoting or narrowing the account narrows the token at once, and disabling or deleting the account revokes it.
- A role. Pick the least-privileged one: a Viewer token covers every read; Operator adds acknowledging alerts and running analyses. Two things no token can do regardless of role: administer users (a credential that could mint its own successor would outlive revoking the original), and use endpoints that mean “the signed-in account”.
- A scope. Which node groups the token may see — the same group scoping an account carries, and honoured on both surfaces. Leave it unset for the whole fleet.
- An optional expiry. Omitting it means no expiry, which is the right answer for a service-account credential driving an integration.
Because a token cannot exceed its owner, a token owned by an already-scoped account
inherits that account’s scope and cannot be given a different one (400 owner_is_scoped). That is the containment you usually want: narrowing the account
narrows every credential it holds, immediately and with nothing to re-issue. To give one
token a narrower view than another, own each with its own service account, scoped to what
that token should see.
Service accounts
Section titled “Service accounts”An unattended credential should not belong to a person: when they change teams, the integration goes with them. A service account (Settings ▸ Users & roles ▸ Add user, account type Service account) is a machine identity with no password that cannot sign in through either the local form or SSO. It exists to own API tokens — so a token survives staff changes, and so that disabling one account stops every credential it owns at once.
The guard that prevents removing the last admin counts only accounts a person can sign in with, so a service account can hold the Admin role without becoming the only administrator.
Issuing and revoking tokens are admin actions and both are audited, every MCP write made with a token records an audit entry naming it, and a token can be revoked at any time from the same page. See Connecting an AI client for putting a token to use.
The audit log
Section titled “The audit log”Every state-changing action — creating or editing configuration, acknowledging an alert, opening a maintenance window, managing users and tokens, and every login — is recorded in an append-only audit log: who did what, when. Writes made through MCP tools are audited the same as writes made through the WebUI, so an AI assistant acting on an Operator token leaves the same trail an operator does.
Admins read it under Settings ▸ Audit log.
Public dashboard mode
Section titled “Public dashboard mode”Yagra can run as a read-open status display: with YAGRA_PUBLIC_DASHBOARD=true, the read
API is served without authentication, so a wallboard or an unauthenticated browser can
see dashboards, node status, and alerts.
The mode opens reads only, and not quite all of them:
- Every write still requires an authenticated session and the matching permission — anonymous viewers can look, not touch.
- MCP always requires a token, even with the public dashboard on. The
/mcpsurface returns unfiltered monitoring data, so it stays authenticated unconditionally. - A few reads stay closed because of what they reveal: the threshold rule set, for example, describes when and whom Yagra will page, so reading it requires the manage-configuration permission and is not exposed to anonymous viewers.
See also
Section titled “See also”- REST API — authentication, the error contract, and the published OpenAPI document.
- Connecting an AI client (MCP) — enabling
/mcpand registering ayat_token with Claude Code, Claude Desktop, or another MCP client. - Security — credential encryption at rest, TLS guidance for the WebUI and API, and what leaves the box.