Skip to content
Lumaft documentation contents
Lumaft documentation

Users and permissions

Bootstrap the first administrator, add accounts, assign roles, issue integration tokens, and secure the installation.

Users and permissions

Lumaft authorizes every request against its own accounts, roles, and permissions. External identity providers can vouch for who a person is; they never decide what that person may do.

The model

  account ──has exactly one──▶ fixed role ──resolves to──▶ permissions ──checked by──▶ every route
                                (administrator | viewer | transcript-reader)

  integration token ───────────────────────────────────▶ operations:evidence:write only
  • Accounts are local users. Each holds exactly one fixed role. Accounts are disabled, never deleted, so audit and evidence attribution always resolve to a real identity.
  • Roles resolve to a set of permissions. Controllers check permissions, never role names.
  • Integration tokens are not accounts. They carry one permission that no role has, and they cannot open the console.
  • Server-side authorization is authoritative. Browser capability checks are presentation only.
Capability Edition
Local accounts with three fixed roles Community
Custom roles composed from the permission catalog Business
Stack read scopes Enterprise
OIDC, SAML, trusted-proxy sign-in, SCIM Enterprise

Bootstrap the first administrator

On first startup, with no local identity in the database, Lumaft reads one password file and creates one administrator. It never bootstraps a second account from a file.

  1. Create a password of 12–4096 characters in a file below a protected directory: parent mode 0700, file mode 0600, owned by UID 1000, no symlinks.
  2. Set LUMAFT_LOCAL_ADMIN_PASSWORD_FILE to its absolute path.
  3. Optionally set LUMAFT_LOCAL_ADMIN_USERNAME before first startup. The default is admin. A username is a lowercase letter followed by up to 63 lowercase letters, digits, periods, underscores, or hyphens.
  4. Start Lumaft and sign in.
  5. Unset LUMAFT_LOCAL_ADMIN_PASSWORD_FILE and securely delete the file.

Lumaft stores an Argon2id-derived credential, never the plaintext. Leaving or changing the file after bootstrap does nothing; it does not rotate the password.

If the database is deleted or replaced with an empty one, the next startup is a new bootstrap and requires the file again.

Recover a lost administrator password

Do not delete the database to regain access; that destroys the evidence Lumaft exists to keep. Use the one-shot file rotation instead:

  1. Create a new password file under the same protection rules.
  2. Set LUMAFT_LOCAL_ADMIN_PASSWORD_FILE to its path and LUMAFT_LOCAL_ADMIN_PASSWORD_ROTATE=true.
  3. Restart once. Startup replaces the credential of the account named by LUMAFT_LOCAL_ADMIN_USERNAME, revokes all of its sessions in the same transaction, and logs one sanitized event. It changes no roles and does not re-enable a disabled account.
  4. Unset both variables and securely delete the file.

While the flag stays set, every startup re-applies the file and revokes sessions again, and logs a warning telling you to remove it. A missing or malformed file fails startup rather than keeping the old credential silently.

For any other account, an administrator resets the password from Users & Access.

Roles and permissions

Fixed roles

Role Holds Does not hold
administrator Every permission except operations:evidence:write and operations:transcripts:read Transcript bodies; evidence submission
viewer backends:read, observations:read, operations:read Any administration; transcript bodies
transcript-reader The viewer's three read permissions plus operations:transcripts:read Any administration

An administrator does not implicitly read transcript bodies. Assign the reader role to a separate account or change an existing account's fixed role deliberately.

Permission catalog

Permission Allows
backends:read Read configured backend metadata
observations:read Read projects, stacks, resources, redacted outputs, locks, update history
operations:read Read the operation timeline and safe resource-change fields
operations:transcripts:read View and download authorized retained transcript bodies
operations:export Create bounded evidence exports
operations:retention:manage Change retention policy; inspect expiry health
operations:purge Perform confirmed scoped deletion
accounts:manage Administer accounts, roles, identity providers, and stack grants
integrations:admin Issue, scope, and revoke integration tokens
backends:diagnostics:read Read backend diagnostic results
storage:health:read Read storage-health, observation-polling, and object-store traffic reports
operations:evidence:write Submit operation evidence — integration tokens only

Add and manage accounts

Requires accounts:manage. There is no self-service signup, invitation flow, or password change for non-administrators.

Add a user from the console

  1. Open Administration → Users & Access.
  2. Under Create account, enter a username (bootstrap rules above), a password of 12–4096 characters, and a role.
  3. Save. Share the password out of band; the user has no way to change it themselves.
ScreenshotUsers & Access page showing the accounts table with role and status columns, and the Create account section with username, password, and role fields

Add a user from the API

curl -fsS -X POST https://lumaft.example.com/api/v1/accounts \
  -H 'Content-Type: application/json' \
  --data '{"username":"m.okafor","password":"<12+ characters>","role":"viewer"}'
Route Purpose
GET /api/v1/accounts List local accounts
POST /api/v1/accounts Create an account by name, password, and role
PUT /api/v1/accounts/:userId/role Assign the account's single fixed role
POST /api/v1/accounts/:userId/password Reset the password and revoke the account's sessions
PUT /api/v1/accounts/:userId/status Disable or enable the account

All account routes are session-authenticated. A bearer token presented to them is refused.

Rules

  • A role change takes effect on the target's next request; sessions re-read roles at verification.
  • Disabling an account or resetting its password revokes its sessions in the same transaction.
  • An administrator cannot demote or disable their own account. The installation always keeps a working administrator.
  • Offboarding is one action: disable the account. Its history and attribution remain.

Integration tokens

Integration tokens are the credential for machine evidence submission — deployment runners and developer machines running lumaft exec. They are administered under integrations:admin (administrators only).

Issue a token

  1. Open Administration → Users & Access and find Issue token.
  2. Provide:
    • Name — for the audit trail, for example ci-deploys or laptop-mokafor.
    • Authority kinddeployment-runner or developer-workflow.
    • Scope — explicit backend, project, and stack patterns. * matches every project (legacy-layout stacks included) or every stack.
    • Expirydeveloper-workflow defaults to 90 days, deployment-runner to none; an explicit 1–365 days overrides either.
  3. Copy the secret (lumaft_it_…). It is shown once. Lumaft stores only its SHA-256 digest.
ScreenshotThe Issue token section showing name, authority kind, and scope pattern fields, with the one-time secret displayed after issuance

Store the secret in a CI secret store or a user-home credential file, never in project files. The wrapper enforces that rule by refusing a token file outside the home directory.

Lifecycle

  • Revocation is immediate and tokens are revoked, never deleted.
  • One active token per name. A revoked token frees its name for a successor.
  • Rotation is issue-successor-then-revoke.
  • Use is audited (last-use time) and failed presentations throttle per client like local sign-in. An authenticated token is limited to 60 requests per minute.
Route Purpose
GET /api/v1/integrations List tokens, including revoked ones
POST /api/v1/integrations Issue a named, scoped token
POST /api/v1/integrations/:tokenId/revoke Revoke immediately

A token authenticates exactly one surface, /api/v1/ingestion/operations, with Authorization: Bearer lumaft_it_…. It never reads state, history, or transcripts, and never opens a browser surface. How a runner uses it is in Runner integration.

Custom roles (Business)

Custom roles let you grant a subset of the catalog — an auditor who can export but not purge, an operator who can manage retention but not accounts — over the same local accounts.

  • A role composes only from the implemented catalog, minus operations:evidence:write.
  • A role cannot grant a permission its author's own session does not hold.
  • Assigning a custom role sets the account's fixed role to viewer in the same transaction, so the fallback whenever custom roles are not entitled is always the viewer baseline.
  • The last enabled fixed administrator cannot take a custom role.
  • A role still assigned cannot be removed.
  • Every act, including refusals, writes one audit row.
Route Purpose
GET /api/v1/roles List custom roles, assignments, and the gate state
POST /api/v1/roles Create a named role from the catalog
PUT /api/v1/roles/:name Replace the role's grant set
DELETE /api/v1/roles/:name Remove an unassigned role
PUT /api/v1/accounts/:userId/custom-role Assign; the fixed role becomes viewer
DELETE /api/v1/accounts/:userId/custom-role Remove the assignment

On license lapse, definitions and assignments are retained read-only and every assigned account operates as a viewer. Re-licensing restores the grants without touching a stored row.

Stack read scopes (Enterprise)

A grant names userId, backendId, projectName (null for a legacy-layout stack), and stackName. There are no wildcards and no deny rules; each user has at most 1,000 grants.

Grants narrow retained-history reads: operations, resource history, reliability, retention audits, exports, and the scope used for transcript reads. They do not grant a permission the role lacks, and live observation pages remain installation-wide — this is not tenant isolation. A user with no grants reads the whole installation. Fixed administrators cannot be scoped.

Route Purpose
GET /api/v1/authorization List grants
POST /api/v1/authorization/grants Add a grant
DELETE /api/v1/authorization/grants/:grantId Remove a grant

Existing grants stay enforced on license lapse.

Federated sign-in (Enterprise)

Federation is additive. Keep a working local administrator and its recovery procedure; a provider outage never removes local sign-in. This section is the reference; step-by-step walkthroughs for Okta and Microsoft Entra ID, plus SCIM setup, are in Federated identity.

Register a provider

From Users & Access → Identity or POST /api/v1/identity/providers, supply:

Field Value
issuerKey 1–64 lowercase letters, digits, or dashes; permanently bound to the issuer
issuer The exact OIDC issuer, SAML entity ID, or proxy realm
provider oidc, saml, or trusted-proxy
provisioningMode administered or on-first-login

Identity is the registered issuer plus the provider's immutable subject. Email, display name, group, and role claims never select, link, or authorize an account.

  • administered — pre-link each subject to an existing user with POST /api/v1/identity/links (issuerKey, subject, userId). An unknown subject fails without creating anything.
  • on-first-login — a verified first sign-in creates a new viewer. It never creates an administrator.

Protocol settings

These are deployment environment variables, separate from the registration. <KEY> is the issuer key uppercased with dashes changed to underscores (corp-idpCORP_IDP). Set LUMAFT_PUBLIC_ORIGIN to the externally reachable HTTPS origin for OIDC and SAML, and apply the same settings to every replica.

Provider Variables Provider-side configuration
OIDC LUMAFT_OIDC_<KEY>_CLIENT_ID, LUMAFT_OIDC_<KEY>_CLIENT_SECRET Authorization-code client; redirect URI <origin>/api/v1/auth/oidc/<issuerKey>/callback; issuer discovery, PKCE, nonce
SAML LUMAFT_SAML_<KEY>_SSO_URL, LUMAFT_SAML_<KEY>_IDP_CERT HTTP-Redirect SSO, signed responses, persistent NameID; SP entity ID <origin>/api/v1/auth/saml/<issuerKey>, ACS at …/acs
Trusted proxy LUMAFT_TRUSTED_PROXY_<KEY>_SUBJECT_HEADER, LUMAFT_TRUSTED_PROXY_<KEY>_SHARED_SECRET Proxy forwards an immutable subject and proves itself with x-lumaft-trusted-proxy-secret (≥ 32 characters)

SAML is SP-initiated only; unsolicited responses and encrypted assertions are refused. OIDC and SAML round trips are single-use and expire after ten minutes. Sign-in starts at /api/v1/auth/<provider>/<issuerKey>/start or from the console's provider action.

For trusted proxy, strip client-supplied identity and proof headers at the proxy, inject verified values, and restrict direct access to the application.

Offboarding a federated user

Disable or unlink the identity to revoke its sessions. Disabling a provider registration stops new sign-ins but does not revoke existing sessions. Do not use license expiry as an offboarding control; configured sign-in paths remain available on lapse.

SCIM provisioning

Issue a registration-bound SCIM token from Users & Access or POST /api/v1/identity/scim-tokens (issuerKey, name). The base URL is <origin>/api/v1/scim/v2/<issuerKey>.

  • Supported: user create, read, replace, patch, delete; ServiceProviderConfig, ResourceTypes, Schemas; filtering by subject equality.
  • externalId must be the same immutable subject used at sign-in. If omitted, userName is the subject, not an email lookup.
  • Creation assigns exactly the viewer role. Delete means deactivate; rows remain.
  • Not supported: groups, bulk, sorting, ETags, password management. Group and role attributes never grant permissions.

Sessions and sign-in protection

  • The session cookie is __Host-lumaft-session: Secure, HttpOnly, SameSite=Strict. Lumaft stores only a SHA-256 digest of the 32-byte token.
  • Sessions have a twelve-hour absolute lifetime. Logout revokes immediately.
  • Five failed attempts from one client address, or for one username/client pair, block further attempts for fifteen minutes. The throttle is process-local; enforce installation-wide limits at your ingress.
  • Authentication failures on the ingestion API return one sanitized 401.
Route Purpose
GET /api/v1/auth/session Read the current authentication state
POST /api/v1/auth/login Verify local credentials and create a session
POST /api/v1/auth/logout Revoke the current session

Securing the deployment

  • TLS everywhere off loopback. The Secure cookie will not survive plain HTTP. Never set LUMAFT_ALLOW_HTTP on a network-reachable deployment.
  • Retire the bootstrap file. Unset LUMAFT_LOCAL_ADMIN_PASSWORD_FILE after first sign-in.
  • Give people their own accounts. Do not share the bootstrap administrator. Create a named administrator per operator and keep the bootstrap account as the recovery path.
  • Default to viewer. Grant administrator only to people who administer. On Business, use custom roles to hand out operations:export or operations:retention:manage without the rest.
  • Separate transcript readers. Transcript bodies are sensitive; the reader role exists so that access is a deliberate, auditable assignment.
  • Scope tokens narrowly. One token per pipeline, scoped to the stacks it deploys, with an expiry where the runner is not permanent. Revoke on rotation; never reuse a secret.
  • Keep the observer identity read-only. Never add operations:evidence:write semantics to the S3 identity or S3 write permissions to the observer. They are different credentials on purpose.
  • Protect the database and its backups like credentials. They contain every account's credential hash, every token digest, and every retained observation.
  • Alert on administration. Account, role, token, retention, purge, and hold actions each write audit rows. On Enterprise, forward the administration core-event feed to your external audit sink.