Skip to content

Authentication

XTM One supports local accounts and single sign-on (SSO) via OIDC and SAML 2.0. All authentication behavior is configured from SettingsSecurity in the UI (admin-only). No environment variables are needed beyond the initial admin bootstrap.

The first account is always an admin

Whichever way the very first account is created — local registration, admin bootstrap, or the first SSO login — it is granted the admin role. Every later account defaults to the standard user role unless promoted.

Local accounts

By default, users authenticate with email and password.

The bootstrap admin account (ADMIN_EMAIL / ADMIN_PASSWORD) is created or reset from environment variables on every startup. If you change that password in the UI, the next restart resets it back to the .env value — keep them in sync.

Local authentication is governed by two toggles under SettingsSecurity:

  • Local Authentication (default: enabled) — allows email/password sign-in. When disabled, local login and local registration are blocked and users must sign in through SSO (an "SSO-only" deployment). The very first account can always be created, even while this is off, so you are never locked out.
  • Local Registration (default: disabled) — lets users self-register with email and password. When disabled, only admins can create accounts.

Restricting registration by email domain

When local registration is enabled, you can restrict it with Allowed email domains (comma-separated; empty means all domains are allowed). Registration from a domain outside the list is refused.

Domain allow-list applies to self-registration only

The allowed-domains list gates local self-registration. It does not filter SSO logins — control SSO access from your identity provider instead.

Admin-managed accounts

Admins manage accounts from the Users page (admin-only). Two mechanisms are available:

  • Create a user directly — add an account and set its role from UsersNew user.
  • Send an invitation link — from UsersInvite user, generate a single-use link bound to a specific email address and role. The invitee sets their own password by opening the link.

How invitation links work

Each invitation is bound to one email address, carries the role you choose, and can be used once. The link expires after a configurable window (default 7 days, set with INVITATION_EXPIRE_HOURS, capped at 30 days). Invitations bypass the Local Registration and Allowed-domains settings, so you can onboard a specific person without opening self-registration to everyone.

Two-factor authentication (TOTP)

Any user can add a second factor: a six-digit code from an authenticator app, entered after the first factor on every sign-in. It is enabled per user from ProfileTwo-factor — there is nothing to configure at deployment level and no environment variable to set.

The factor is XTM One's own, and it applies whichever way the user signs in — local password, OIDC, or SAML. It is not delegated to the identity provider. That is deliberate: many deployments federate to a provider whose MFA policy they do not control (a customer tenant, a partner IdP, a legacy directory), and being able to enforce a second factor at the application boundary is the point. Where the IdP already enforces one, the two simply stack, and users are free not to enroll.

Any RFC 6238 authenticator app works, including Google Authenticator, Microsoft Authenticator, KeePassXC, 1Password, Bitwarden, Aegis and FreeOTP. XTM One uses the parameters those apps assume by default (SHA-1, 6 digits, 30-second period), so enrollment is a QR scan with no per-app tuning. The QR is rendered by your own server, so enrollment works on air-gapped deployments — no third-party service is contacted.

Enrollment is two-phase on purpose: scanning the QR is not enough, the user must type a code back to prove the app was enrolled correctly. Until they do, nothing changes about how they sign in — closing the tab halfway cannot lock anyone out.

Recovery codes

Enabling two-factor issues 10 single-use recovery codes, displayed once and never again. Each one signs the user in once, in place of the app, if they lose their device. Users can generate a fresh set (invalidating the old one) from their profile, which requires a current code from the app.

If a user loses their device and their codes

An admin can clear the enrollment from the user's detail page (Users → select the user → Two-factorReset two-factor). The account then signs in with its password alone until the user enrolls a new device. The action is audited.

Administrators never see the secret

The TOTP secret is encrypted at rest with the platform SECRET_KEY, and recovery codes are stored hashed. Neither can be read back by anyone, including admins — resetting is the only recovery path, and it deliberately forces a fresh enrollment.

Rotating SECRET_KEY invalidates every enrollment

The encryption key for stored secrets is derived from SECRET_KEY. Changing it leaves existing enrollments unreadable: affected users can still sign in with a recovery code, and admins can reset their enrollment, but their authenticator app stops working.

How it works with SSO

After a successful OIDC or SAML assertion, an enrolled user is returned to the sign-in page for the code step instead of being signed in. No session token is issued until the code is verified, so the extra factor cannot be skipped by replaying the callback URL.

An SSO-only user disables their factor with a code alone — they have no XTM One password to confirm with. Accounts that do hold a local password are asked for both.

Until the code is accepted, the audit log records the event as "Authenticated via OIDC, awaiting second factor", not as a completed login. The completed login is recorded separately, and names the provider it came through.

Local authentication can stay disabled

Two-factor does not require enabling local passwords. An SSO-only deployment (Local Authentication off) can enroll every user in an authenticator app and keep the IdP as the sole first factor.

Scope

Two-factor applies to interactive sign-in — local, OIDC, and SAML alike.

API keys (fcp-…), channel bots and cross-platform tokens from OpenCTI/OpenAEV are unaffected: they are machine credentials with nowhere to prompt for a code.

Enabling, disabling, recovery-code use and failed verifications are all recorded in the audit log, under the mfa entity type. Each entry is attributed to the flow it came from via its actionlogin, enable, disable, or update (regenerating recovery codes) — so the audit filters separate a failed code at sign-in from a mistyped one while turning the factor off.

That separation is what makes the log useful for detection: a run of failed second factors with action login and no matching successful login is the signal that someone holds a password but not the device.

OIDC (OpenID Connect)

Use OIDC to integrate with identity providers such as Microsoft Entra ID (Azure AD), Okta, Google Workspace, or Keycloak. OIDC uses the Authorization Code flow.

What you need

  • A registered OAuth 2.0 / OIDC application in your IdP
  • A Client ID and Client Secret
  • Either a Discovery URL (the .well-known/openid-configuration endpoint — recommended) or the individual authorization, token, and userinfo endpoint URLs
  • The Redirect URI registered in your IdP: {BASE_URL}/api/auth/oidc/callback

Configuration

Configure OIDC from SettingsSecurity. The fields are:

Field Notes
Display Name Label shown on the sign-in button (e.g. "Microsoft")
Discovery URL Recommended — auto-resolves the other endpoints
Client ID / Client Secret From your IdP application; stored encrypted
Scopes Default openid email profile
Manual endpoint URLs Optional — set the authorization, token, and userinfo URLs directly if you are not using discovery

The exact Redirect URI to register in your IdP is displayed in the configuration panel.

User provisioning

Users are created automatically on first login. XTM One matches the identity in this order:

  1. By the SSO subject (sub) of a previously linked account.
  2. Otherwise by email — if a local (or other) account with the same email exists, it is linked to the OIDC identity.
  3. Otherwise a new account is created.

The IdP must return an email claim; a login with no email is rejected. The user's name and job title are updated from the IdP claims on each login.

On-the-fly user creation

An On-the-fly user creation toggle (default: on) controls step 3 above. When disabled, only pre-provisioned accounts can sign in via OIDC: an identity that matches no existing account (by SSO subject or email) is refused before any account is created, and the person is sent back to the login page with a readable message (?sso_error=not_provisioned). Steps 1 and 2 are unaffected — existing accounts keep signing in and linking by email as before.

Use this when account creation must go through an explicit administrative step (invitations, an IdP-side approval flow, or manual provisioning) rather than being implied by IdP access.

Automatically admin users

An optional Automatically admin users toggle (default: off) grants the admin role to anyone who signs in via OIDC. It is promote-only — it never demotes existing admins, and turning it off later does not strip roles already granted. OIDC does not support group mapping; use SAML if you need group-driven roles.

When sign-in fails

Changed behaviour. A failed or abandoned OIDC sign-in used to leave the browser on a raw JSON error — an API error body, or a validation error about a missing code parameter. It now returns to the login page with a readable message and a marker in the URL:

?sso_error= When What the person sees
cancelled They declined the consent screen at the identity provider Sign-in was cancelled; try again when ready
not_authorised The XTM Hub entitlement gate declined them (see below) Their account is not authorised for this instance
not_provisioned On-the-fly user creation is disabled and no account matches their identity No account exists; ask an administrator to create one first
failed Any other provider error, or a malformed callback Single sign-on failed; contact your administrator

This applies to every OIDC deployment, whether or not the XTM Hub gate below is configured. Nothing about who can sign in changes — only how a failure is presented.

The message is deliberately vague in every case. The specifics — the provider's error code and description, or the reason an account was not entitled — are written to the server log, because someone who has not signed in should not be able to read your identity provider's configuration back out of an error page. The marker is scrubbed from the URL once shown, so a reload does not re-accuse someone who has since signed in successfully.

XTM Hub entitlement gate

If this instance is federated through XTM Hub, the Hub can decide which XTM One instances each person may reach, and whether they are an administrator on each one. Set XTM_HUB_ADMIN_GROUP to switch it on — see Configuration. The gate identifies this instance by its PLATFORM_ID, which must be set too.

It is off unless configured, and when on it takes precedence over Automatically admin users above: that toggle only promotes, while the Hub also demotes.

Two consequences are worth knowing before you enable it:

  • A person the Hub has not entitled here is refused before an account is created, so no dormant accounts accumulate — but an existing user who loses their entitlement is also refused on their next sign-in.
  • Administrator is removed when the Hub stops asserting it. The ADMIN_EMAIL account is never demoted for exactly this reason, and local sign-in remains available as a recovery path if the gate is misconfigured.
  • Every role change the Hub causes is written to the audit log, in the same shape as one made from the admin UI, so "who became an administrator, and when" has one answer regardless of who decided it.

SAML 2.0

Use SAML for enterprise identity providers that require SAML assertions. XTM One acts as the Service Provider in an SP-initiated flow.

What you need

  • Your IdP metadata URL (or XML)
  • The ACS (Assertion Consumer Service) URL: {BASE_URL}/api/auth/saml/acs
  • The Entity ID / SP metadata URL: {BASE_URL}/api/auth/saml/metadata

Configuration

Configure SAML from SettingsSecurity. The fields are:

Field Notes
Display Name Label shown on the sign-in button (e.g. "Corporate SSO")
IdP Metadata URL Your identity provider's federation metadata
SP Entity ID Optional — leave empty to use the metadata URL

User provisioning

Users are created automatically on first login, matched by email in the same order as OIDC (SSO subject, then email linking, then create).

SAML has the same On-the-fly user creation toggle as OIDC (default: on). When disabled, an assertion that matches no existing account is refused before any account is created and the browser returns to the login page with ?sso_error=not_provisioned.

Automatically admin users

Like OIDC, SAML has an Automatically admin users toggle (default: off) that grants the admin role on SAML login. It is promote-only.

Group mapping

SAML supports automatic group mapping from IdP group claims (enabled by default). XTM One reads groups from the common claim URIs used by Microsoft Entra ID, Okta, ADFS, and generic SAML providers.

  • Groups from the assertion are synced on every login: the user is added to matching XTM One groups and removed from groups no longer present in the assertion.
  • With Auto-create groups enabled (default), groups in the assertion that do not yet exist in XTM One are created automatically.

Both settings live under the SAML section of SettingsSecurity. See Groups for how groups control entity sharing.

Terms of Use acceptance

After signing in — with any method above — users are shown a blocking Terms of Use screen and cannot reach any part of the UI until they explicitly accept. Acceptance is recorded server-side (account, version, timestamp) and the gate is enforced on the API too, so it cannot be skipped by calling the backend directly.

The gate only applies where Agentic AI is licensed. Community Edition deployments never see it.

Variable Default Purpose
TERMS_OF_USE_ENABLED true Set to false to disable the gate entirely — for deployments that handle Terms of Use acceptance outside the product.
TERMS_OF_USE_VERSION 2026-07-14 Identifier of the published document. An empty value disables the gate.
TERMS_OF_USE_URL https://filigran.io/ai-terms/ Where the document is published. The screen links to it; it is not embedded.

Changing the version re-prompts everyone

Users are gated whenever their recorded acceptance does not match TERMS_OF_USE_VERSION. Bumping it is how you roll out a revised document: every user is asked to accept again on their next request, including those who had already accepted the previous version. There is no admin UI toggle — a revision is a deliberate configuration change.

Admins can review acceptance on the Users page: each account shows whether it has accepted the current version, and its detail page shows the accepted version and date.

Access provisioning summary

Method How users are created Where
Admin creates a user Admin adds an account and sets its role UsersNew user
Admin invitation link Single-use, email-bound link the invitee opens to set a password UsersInvite user
Self-registration Users register with email and password (optionally domain-restricted) Sign-in page, when Local Registration is enabled
SSO auto-provisioning Users are created on first OIDC or SAML login, linked by email On first SSO login

Account hardening summary

Hardening What it adds Where
Two-factor (TOTP) A six-digit code from an authenticator app, required after the password ProfileTwo-factor (per user)
Admin reset of two-factor Clears an enrollment for a user who lost their device Users → user detail → Reset two-factor

Next step

Once authentication is configured, proceed to Administration to manage users, groups, and permissions.