Authentication modes
Pitot supports local sign-in and OIDC, selected by PITOT_AUTH_MODE.
Both use the same roles and capabilities, browser sessions
and account suspension rules.
Active users sign in with an emailed code when SMTP is configured. Without
SMTP, an operator with access to the control database mints a single-use link
with pitot login-link <email>. Administrators manage accounts and roles
through the HTTP API. There is no user-management browser page. See
account profiles and suspension
for account APIs and local recovery for invitation delivery
and recovery.
PITOT_SELF_SIGNUP allows verified email addresses to create viewer accounts.
It defaults to false and requires complete SMTP configuration. Self-signup is
available only after the first administrator completes setup. Viewers can read
all telemetry, manage their own dashboards and run the built-in agent.
The built-in agent sends requests to your configured model provider and can
incur charges. Enabling self-signup grants that access to anyone who can verify
an email address.
An identity provider handles sign-in. Group and domain allowlists are evaluated on every login, including for linked identities. Removing a user’s eligibility blocks their next login; it does not revoke a browser session already issued. Suspending the account in Pitot blocks access and revokes its sessions.
Pitot starts even when the identity provider is unreachable, so ingest, MCP
and existing sessions keep working. Discovery retries in the background with
backoff capped at 1 minute. Until it succeeds, the OIDC sign-in routes return
503 and the oidc check in /readyz reads degraded; no restart is needed.
Invalid configuration, including a provider that answers for a different
issuer at startup, still fails startup.
If neither PITOT_OIDC_ALLOWED_GROUPS nor PITOT_OIDC_ALLOWED_DOMAINS is
configured, no eligibility allow policy is enforced. Membership is then managed
locally, unless a role mapping is set; see Who owns accounts.
Account provisioning
Section titled “Account provisioning”PITOT_OIDC_AUTO_PROVISION creates eligible accounts on first sign-in after
administrator setup. It requires an allowed group or domain. The role comes
from the configured group mapping, falling back to PITOT_OIDC_DEFAULT_ROLE
(viewer).
PITOT_OIDC_EMAIL_VERIFICATION=required requires a verified email. The issuer
policy trusts the configured issuer and requires an allowlist. See
Microsoft Entra ID group overage if group
claims are omitted.
Role ownership
Section titled “Role ownership”If PITOT_OIDC_ADMIN_GROUPS or PITOT_OIDC_OPERATOR_GROUPS is configured, the
provider reapplies the mapped role on every login. Users outside mapped groups
receive PITOT_OIDC_DEFAULT_ROLE. A role change revokes browser sessions and
writes an audit event in the same transaction.
Without a role-group mapping, administrators manage roles inside Pitot and OIDC sign-in preserves them. Reconciliation cannot demote the last active administrator; promote a second administrator before applying that mapping.
Who owns accounts
Section titled “Who owns accounts”Role mapping moves account ownership to the identity provider.
GET /api/auth/status reports the mode as account_ownership, and Settings
explains it to signed-in users.
account_ownership | Configuration | Browser user routes refuse |
|---|---|---|
local | No role mapping, with or without a SCIM token | Nothing |
identity_provider_roles | Role mapping and PITOT_OIDC_AUTO_PROVISION, no SCIM token | Creating a user and changing a role |
identity_provider_roles_no_provisioning | Role mapping, no PITOT_OIDC_AUTO_PROVISION, no SCIM token | Creating a user and changing a role |
identity_provider_directory | Role mapping and a SCIM token | Creating and deleting a user; changing a role, status or email |
To add users under a role mapping, set PITOT_OIDC_AUTO_PROVISION with an
allowed group or domain, or configure a SCIM token. With neither, nobody new can
get an account: POST /api/users is refused and a first login is denied. Pitot
still starts, logs a warning, and Settings says so.
A refused request returns 403 with the code managed_by_identity_provider
and changes nothing. On PATCH /api/users/{id}, malformed JSON returns 400
because the body must be decoded to see whether email is present. SCIM, login-time role reconciliation and provisioning,
display-name edits, POST /api/users/{id}/access/revoke, first-administrator
setup and pitot login-link --break-glass keep working in every mode.
Without a SCIM token, administrators can still suspend, reactivate, delete and
change the email of a user.
Microsoft Entra ID group overage
Section titled “Microsoft Entra ID group overage”Entra can omit the groups claim when an account has too many memberships.
If the token signals group overage and any group-based policy is configured,
Pitot denies login. It does not fetch group membership from Graph.
Configure the application registration to emit only groups assigned to the
application. Domain-only allow policies are unaffected.
Account profiles and suspension
Section titled “Account profiles and suspension”Administrators create active accounts with POST /api/users, supplying email,
display_name and role. Edit profiles with PATCH /api/users/{id}; change
roles with PATCH /api/users/{id}/role and {"role":"viewer"}. Suspend with
PATCH /api/users/{id}/status and {"status":"suspended"}; restore with
{"status":"active"}. Unknown fields and invalid statuses return 400.
Email, role and status changes revoke browser sessions. Suspension blocks local
and OIDC sign-in and revokes the user’s OAuth tokens. Reactivation revokes any
that remain, so a reactivated user signs in again. The last active administrator cannot be demoted, suspended or deleted.
With an OIDC role mapping some of these routes are refused; see
Who owns accounts.
GET /api/users returns a users array. DELETE /api/users/{id} removes an
account and cascades to its sessions, OAuth grants and owned dashboards. Use
suspension when the account and its data should remain.
POST /api/users/{id}/access/revoke revokes all browser sessions and OAuth
tokens for that user. It preserves the account. A user who remains eligible
can sign in again.
Call account APIs from a script
Section titled “Call account APIs from a script”These routes accept only a browser session with the admin role. Pitot has no API key for user administration. Ingest tokens, metrics tokens and MCP OAuth tokens cannot substitute for that session.
Sign in as an administrator. In browser developer tools, find an authenticated request and copy its session cookie into a temporary Netscape-format cookie jar supported by curl. Keep it private and outside source control. A script can use that jar while the session remains valid:
curl --fail-with-body --cookie "$COOKIE_JAR" \ https://pitot.example.com/api/users
curl --fail-with-body --cookie "$COOKIE_JAR" \ -H 'Pitot-Request: 1' -H 'Content-Type: application/json' \ -X POST https://pitot.example.com/api/users \Replace the origin and set COOKIE_JAR to that private jar. Mutating requests
need Pitot-Request: 1 or a matching Origin/Referer; cross-site browser requests
are rejected. Session expiry or revocation requires signing in again. Delete
the temporary jar when finished and sign out to revoke that session.
SCIM provisioning
Section titled “SCIM provisioning”Set PITOT_SCIM_TOKEN (or PITOT_SCIM_TOKEN_FILE) so an identity provider or
automation can create, update and deactivate accounts. It requires
PITOT_AUTH_MODE=oidc and at least 32 characters. Without a token the routes
do not exist.
With a token, Pitot prints no setup banner and /api/auth/setup returns 410;
the first administrator comes from SCIM.
Pitot implements a small subset of SCIM 2.0 under /scim/v2. Send
Authorization: Bearer <token>. Responses and errors use
application/scim+json and the RFC 7644 formats.
POST /scim/v2/Userscreates an account fromexternalId,userName(the email address) and onerolesvalue ofadmin,operatororviewer. The account and its identity at the configured issuer are written together, so the first OIDC login needs no match by email. Repeating the request returns the existing account with200and changes nothing.GET /scim/v2/Users?filter=externalId eq "<subject>"finds an account.userName eq "<email>"also works. Other filters returninvalidFilter.PATCH /scim/v2/Users/{id}changesactive, the role, the email anddisplayName. Resending the current values writes nothing.
An email held by a different account returns 409. While there are no users,
only an active administrator can be created. Deactivating or demoting the last
active administrator returns 409.
Deactivation revokes the user’s browser sessions and MCP tokens. Reactivation restores neither, and keeps the identity link. See docs/authentication.md for the full contract.
Recover local sign-in
Section titled “Recover local sign-in”Run with the server’s environment and data directory:
# For Docker:The URL is printed to stderr, expires in 15 minutes and works once. Issuance
and redemption are audited. The command supports an online server but refuses
missing or suspended users, a missing control database and OIDC mode without
--break-glass.
Creating a local user without SMTP returns 201,
invite_delivery: "not_configured" and login_link_required: true. Mint a link
for that active user and deliver it through a trusted channel. If configured
SMTP fails delivery, the API reports an error. Repair SMTP after regaining access.
If the only administrator is suspended or has an unusable address, stop Pitot and back up the control database. Repair that existing account’s email or status in SQLite, preserving its ID and owned data. Restart and mint a login link for the active account.
OIDC break-glass recovery
Section titled “OIDC break-glass recovery”If the identity provider is unavailable, run this with the server’s environment and data directory to issue a one-time link for an active administrator:
# For Docker:Set PITOT_AUTH_CODE_SECRET with at least 32 characters before you need this.
OIDC mode does not require it at startup, but without it the command fails and
the server keeps login links disabled. Pitot starts while the provider is
unavailable, so this also works after a restart during the outage.
The command refuses other roles, suspended users and local mode. The URL expires
in 15 minutes and works once. In OIDC mode, the server accepts only these links
and re-checks that the account is still an active administrator. Issuing and
redeeming write the distinct audit events login_link.break_glass_issued and
login_link.break_glass_redeemed. If the redemption event cannot be written,
Pitot creates no session and the request fails; the link is spent, so issue a
new one.
/api/auth/link/verify is rate limited per client address. Behind a reverse
proxy, set PITOT_TRUSTED_PROXY_CIDRS; otherwise every request shares the
proxy’s address and one limit, and other traffic can block recovery.
Review MCP connections
Section titled “Review MCP connections”Open Connect telemetry → Connected agents in the account menu to review and disconnect one OAuth client. Disconnecting revokes that client’s access and refresh tokens for your account. Reconnect by authorizing it again. Other clients and browser sessions remain connected. See MCP connections for API routes.
Access boundaries
Section titled “Access boundaries”See namespace access limits. Dashboard access is scoped to the owner for every role, including administrators.