Skip to main content

Users

A user in Liberty is the identity that signs in and carries roles. The Settings → Access → Users tab is where you create local users, see OIDC users that have signed in at least once, assign roles, and toggle the active and superuser flags.

The same UI manages both identity backends (TOML / DB) and both identity sources (local / OIDC). The differences land on what fields are editable: OIDC users have no password (it's at the IdP), and their provider field is read-only.


The Users tab

Settings · Access👤 Users🛡 Roles+ Add useradminAdmin User · admin@corp.local · localsuperuseradminaliceAlice Martin · alice.martin@corp.local · oidcanalystreporterbobBob Dupont · bob@corp.local · localinactivereaderClick a row to open the User editor.

Each card shows the username (monospace), full name, email, provider (local / oidc), the status chips and the assigned roles.

ChipMeaning
superuser (orange)is_superuser = true — bypasses every permission check.
inactive (red)is_active = false — the user can't sign in. Their existing sessions stop on next token refresh.
No roles (muted)No roles assigned and not a superuser — the user signs in but sees nothing.
Role names (purple)Each assigned role, one chip per role.

Add a local user

Click + Add user. The User editor opens with every field empty.

Add userUsername *aliceFull name(optional)Alice MartinEmail(optional)alice@corp.localPassword *(8+ chars)••••••••••Rolesanalyst ✕reporter ✕Pick a role…Activethe user can sign inSuperuserbypasses every permission checkCancelSave

Fields

FieldRequiredNotes
UsernameyesLetters, digits, underscores, dots and hyphens. Used as the sign-in handle, the JWT subject, and the audit identity. Immutable after creation.
Full namenoThe display name shown in headers and audit columns.
EmailnoRecipient address for invites, password reset (when implemented), notification routes.
Passwordyes (for new users)At least 8 characters. Stored as an Argon2id hash, never readable back. Leave blank on edit to keep the current password.
RolesnoChip picker — type or pick from the dropdown. The dropdown lists every role configured under the Roles tab.
Activeyes (default on)When off, the user can't sign in; existing sessions die on next token refresh.
SuperusernoWhen on, bypasses every permission check. Use sparingly.

Click Save — the user is created and the modal closes. The new user appears at the top of the list.

Endpoints behind the scenes

ActionEndpoint
CreatePOST /admin/access/users
UpdatePATCH /admin/access/users/{username}
Password changePOST /admin/access/users/{username}/password

The TOML backend writes to config/auth.toml atomically; the DB backend commits to ly2_users / ly2_user_roles. Either way, the change takes effect immediately — the user can sign in with the new password right away.


Edit an existing user

Click any user row to open the editor with their current values:

FieldEditableNotes
UsernamenoPinned at creation.
Full name / EmailyesUpdate freely.
Passwordyes (local users only)Leave blank to keep the current password. Typing a new one (8+ chars) sets it on Save.
RolesyesAdd / remove chips.
ActiveyesToggle to deactivate.
SuperuseryesToggle to grant / revoke superuser.

Saves go through PATCH /admin/access/users/{username} for the property updates and POST /admin/access/users/{username}/password if a new password was typed.

When the user is signed in

Changes don't break their current session. The new roles / disabled flag / password take effect on the next refresh (within the access token TTL — default 1 hour) or sign-out + sign-in.


OIDC users — the differences

OIDC users land in the Users list after their first sign-in — Liberty auto-creates them with provider = "oidc". The editor for an OIDC user looks the same, but:

FieldEditable for OIDC?Notes
UsernamenoSame as local.
Full name / Emailtechnically yes, but…On every OIDC sign-in, these fields are refreshed from the IdP claims. Manual edits get overwritten. Edit them at the IdP instead.
PasswordnoThe IdP holds the password. The field is disabled or rejected with HTTP 400.
RolesyesThis is the main reason operators visit OIDC users — to assign roles.
ActiveyesWhen off, sign-in is rejected even with valid OIDC tokens.
SuperuseryesToggle to grant the bypass.

The standard onboarding sequence:

  1. The new hire signs in via OIDC for the first time.
  2. They land with no roles → they see an empty app.
  3. They tell their admin "I'm in but see nothing".
  4. The admin opens Settings → Access → Users, finds them, assigns the right roles, saves.
  5. The user refreshes the page (or signs out + back in) and now has access.

For installs that want to pre-create OIDC users with roles already attached, scripts can hit POST /admin/access/users with provider = "oidc" and the expected provider_subject (the sub claim). On first sign-in the framework finds the pre-created user and uses it. Standard installs skip this and assign roles after first sign-in.


Deactivating vs deleting

Two ways to take a user out:

OptionEffectWhen
Toggle Active offUser can't sign in. Their current session continues until the access token expires (default 1 h), then refresh fails. Roles, history and audit trail preserved.Maintenance, leave of absence, suspended account.
🗑 Delete (per-row action, with confirm)User removed entirely. Their history is preserved (audit rows are immutable), but the username can be re-used.Departure, GDPR right-to-erasure.

Deactivation is reversible in one click. Deletion is final — the user re-signing in (OIDC) would auto-create a new account with the same username but fresh id and no carryover of roles.


What you actually do — typical workflows

Onboard a local hire

  1. Settings → Access → Users → + Add user.
  2. Username = corporate handle, password = a one-time string they'll change, email = their address.
  3. Assign roles per their team (analyst, reporter, …).
  4. Save.
  5. Send them the temporary credentials through whatever channel your company uses.
  6. They sign in, they reach the AI assistant or change-password flow to set their own password.

Onboard an OIDC hire

  1. They sign in via OIDC the first time — Liberty auto-creates the account.
  2. They report no access.
  3. Settings → Access → Users, find them, assign roles, save.
  4. They refresh → they're in.

Change a user's password (you're the admin)

  1. Settings → Access → Users, click the user.
  2. Type the new password in the Password field (8+ chars).
  3. Save.
  4. Tell the user. They sign in with the new password; their existing session keeps working until the access token expires.

Revoke an account immediately

  1. Toggle Active off and save.
  2. If you can't tolerate the up-to-1-hour delay until their current access token expires, rotate the JWT signing secret ([auth] jwt_secret in app.toml or LIBERTY_JWT_SECRET env var) and restart. Every existing token is invalidated — a heavy hammer but the only immediate revocation Liberty offers.

Common pitfalls

MistakeSymptomFix
OIDC user has no roles after sign-in.Expected — the operator hasn't assigned any yet.Open Settings → Access → Users, assign roles.
Editing an OIDC user's email reverts on next sign-in.The IdP claim wins; the framework refreshes from the latest token.Edit the email at the IdP.
Trying to set a password for an OIDC user.Backend rejects with 400.OIDC users have no local password — they sign in through the provider.
Changing a user's role doesn't take effect immediately.The user's JWT still has the old roles.They refresh (or sign-out + sign-in) — within the access token TTL the new roles apply.
Deleting and recreating a user to "reset" them.Their audit history detaches (now references a deleted username).Use deactivate + reactivate; only delete when the user is truly gone.
Marking a user superuser to fix a permission gap.Works, but bypasses every check — including ones the user shouldn't be bypassing.Add the missing permission to one of their roles instead.

What's next