System Administration encompasses all functions related to managing users, authentication, workspace access control, audit logging, and system-wide settings in AnythingLLM. This includes both single-user and multi-user deployment modes, with robust role-based access control (RBAC) in multi-user environments.
For LLM provider configuration and vector database settings, see Configuration Management. For workspace-specific settings and document management, see Workspace Management.
AnythingLLM supports four authentication modes with distinct token management strategies. The mode is determined by checking SystemSettings.isMultiUserMode() in middleware.
Authentication Mode Diagram
Sources: server/endpoints/system.js183-334 server/endpoints/system.js336-377 server/utils/http.js
<old_str>
Multi-user mode is enabled via POST /system/enable-multi-user at server/endpoints/system.js591-644 This endpoint:
response.locals.multiUserMode at line 596User.create({ username, password, role: ROLES.admin }) at lines 604-609SystemSettings._updateSettings({ multi_user_mode: true }) at line 619updateENV() at lines 624-629The login flow at server/endpoints/system.js183-334 performs:
simpleSSOLoginDisabled() at line 188User._get({ username: String(username) }) at line 200bcrypt.compareSync(String(password), existingUser.password) at line 220if (existingUser.suspended) at line 238makeJWT({ id: existingUser.id, username: existingUser.username }, process.env.JWT_EXPIRY) at lines 273-276generateRecoveryCodes(existingUser.id) at line 278Event logging for failed attempts:
failed_login_invalid_username at lines 203-210failed_login_invalid_password at lines 222-235failed_login_account_suspended at lines 239-253Sources: server/endpoints/system.js183-334 server/endpoints/system.js591-644 server/models/user.js </old_str>
<new_str>
In single-user mode, authentication relies on the AUTH_TOKEN environment variable. The login flow at server/endpoints/system.js296-329 performs:
reqBody(request) at line 297bcrypt.compareSync(password, bcrypt.hashSync(process.env.AUTH_TOKEN, 10)) at lines 299-301EventLogs.logEvent("failed_login_invalid_password") at line 304makeJWT() at lines 323-326 with encrypted payload:
The EncryptionManager class at server/utils/EncryptionManager.js encrypts the password to prevent plaintext storage in the JWT.
Sources: server/endpoints/system.js296-329 server/utils/EncryptionManager.js
In single-user mode, authentication relies on a password stored in the AUTH_TOKEN environment variable. The login flow at server/endpoints/system.js230-263 compares the submitted password against the hashed AUTH_TOKEN. On successful authentication, a JWT token is generated containing an encrypted password payload using the EncryptionManager class.
The JWT is created via makeJWT() at server/endpoints/system.js257-260 with a payload structure:
Simple SSO provides token-based authentication via GET /request-token/sso/simple at server/endpoints/system.js336-377 The flow:
temporary_auth_tokens table/sso/simple?token=<tempToken>TemporaryAuthToken.validate(tempAuthToken) at lines 341-342, which:
users tablemakeJWT() at line 373The simpleSSOEnabled middleware at line 338 enforces SSO is enabled. Login via credentials can be blocked using simpleSSOLoginDisabledMiddleware which is applied to invite creation at server/endpoints/admin.js177
Sources: server/endpoints/system.js336-377 server/models/temporaryAuthToken.js server/utils/middleware/simpleSSOEnabled.js
API keys provide programmatic access without session management. The validApiKey middleware at server/utils/middleware/validApiKey.js validates keys for /v1/* API routes by:
Authorization headerapi_keys table via ApiKey.get({ secret: apiKey })response.locals.userIn multi-user mode, API keys are created with createdByUserId foreign key linking to the users table. In single-user mode, the createdByUserId field is null.
Sources: server/utils/middleware/validApiKey.js server/models/apiKeys.js
RBAC Architecture Diagram
Sources: server/utils/middleware/multiUserProtected.js39-158 server/utils/helpers/admin.js server/endpoints/admin.js35-497
Three roles are defined in the ROLES constant at server/utils/middleware/multiUserProtected.js39-42:
| Role | Database Value | Permissions |
|---|---|---|
admin | "admin" | Full system access: LLM/vector DB config, all user/workspace operations, system settings |
manager | "manager" | User and workspace management, invite creation, workspace chat viewing, security/branding settings |
default | "default" | Workspace access controlled via workspace_users table, can update own profile |
The all pseudo-role matches any authenticated user and is used for endpoints like profile picture upload.
Sources: server/utils/middleware/multiUserProtected.js39-42
Two primary middleware functions enforce role-based access:
strictMultiUserRoleValid([roles]) at server/utils/middleware/multiUserProtected.js125-158
isMultiUserSetup(response)userFromSession(request, response)flexUserRoleValid([roles])(request, response, next)/admin/users, /admin/invites, /admin/workspacesflexUserRoleValid([roles]) at server/utils/middleware/multiUserProtected.js88-123
!multiUserMode(response)), allows all accessuserFromSession(request, response)ROLES.all specified/system/update-env, /system/event-logs, /system/pfp/:idSources: server/utils/middleware/multiUserProtected.js88-158
The admin helper functions at server/utils/helpers/admin.js provide fine-grained authorization logic called by endpoints before user modifications:
validRoleSelection(currentUser, newUserData)
currentUser.role === "manager" and newUserData.role === "admin"{ valid: boolean, error: string }POST /admin/users/new and line 101 in POST /admin/user/:idcanModifyAdmin(targetUser, updates)
users table via User.count({ role: "admin", suspended: 0 }){ valid: boolean, error: string }User.update() in POST /admin/user/:idvalidCanModify(currentUser, targetUser)
currentUser.role === "manager" and targetUser.role === "admin"{ valid: boolean, error: string }POST /admin/user/:id and line 135 in DELETE /admin/user/:idSources: server/utils/helpers/admin.js server/endpoints/admin.js49-156
User Management Flow Diagram
Sources: server/endpoints/admin.js49-124
User Management Flow Diagram
Sources: server/endpoints/admin.js35-156
User creation is handled by the /admin/users/new endpoint at server/endpoints/admin.js49-83 The flow:
userFromSession() at server/endpoints/admin.js54validRoleSelection() at server/endpoints/admin.js56User.create(newUserParams) at server/endpoints/admin.js65Required fields for user creation:
username - String, validated by User.validations.username()password - String, hashed with bcrypt before storagerole - One of: admin, manager, defaultOptional fields:
suspended - Boolean, defaults to 0 (false)The User.create() method at server/models/user.js performs:
users table{ user, error } with filtered user dataUser updates via POST /admin/user/:id at server/endpoints/admin.js85-124 perform three authorization checks:
validCanModify(currUser, user) - Ensures current user can modify target user (managers cannot modify admins)validRoleSelection(currUser, updates) - Validates role change is permitted (managers cannot assign admin role)canModifyAdmin(user, updates) - Prevents demoting/suspending last adminEach check returns { valid: boolean, error: string }. If any check fails, the endpoint returns 200 { success: false, error } without modifying the user.
Example Update Payload:
All fields are optional. The User.update(id, updates) method at line 117:
users table record{ success: boolean, error: string | null }Sources: server/endpoints/admin.js85-124 server/models/user.js
User deletion via DELETE /admin/user/:id at server/endpoints/admin.js126-156 performs:
User.get({ id: Number(id) }) from users tablevalidCanModify(currUser, user)User.delete({ id: Number(id) })The User.delete() method cascades to related records:
workspace_users table (workspace access)api_keys table (API keys created by user)invites table (invites created by user)Sources: server/endpoints/admin.js126-156 server/models/user.js
Users can update their own profile via POST /system/user (referenced in frontend/src/models/system.js680-691) without admin permissions. This endpoint:
validatedRequest middleware (no role check)userFromSession(request, response)username, password, bio, pfpFilenameUser.update(user.id, data) with provided fieldsUsers can also upload/remove profile pictures via:
POST /system/upload-pfp at server/endpoints/system.js764-802 with handlePfpUpload multer middlewareDELETE /system/remove-pfp at server/endpoints/system.js855-889Sources: server/endpoints/system.js764-889 frontend/src/models/system.js680-691 server/models/user.js
Workspace Access Control Diagram
Sources: server/endpoints/admin.js224-320 server/endpoints/api/admin/index.js425-660
The /admin/workspaces endpoint at server/endpoints/admin.js224-236 returns all workspaces with their associated users via Workspace.whereWithUsers(). This method joins the workspaces, workspace_users, and users tables to return:
The /admin/workspaces/:workspaceId/users endpoint at server/endpoints/admin.js238-251 calls Workspace.workspaceUsers(workspaceId) which queries the workspace_users join table to return user associations for a specific workspace.
Workspace creation at server/endpoints/admin.js253-270 uses Workspace.new(name, userId) which:
{ workspace, message }Two methods control workspace access:
Workspace.updateUsers(workspaceId, userIds) at server/endpoints/admin.js272-289
workspace_users records for the workspace/admin/workspaces/:id/update-users endpointWorkspaceUser.createManyUsers(userIds, workspaceId)
/v1/admin/workspaces/:slug/manage-users endpoint at server/endpoints/api/admin/index.js547-660The API endpoint supports two modes via the reset parameter:
reset: true - Calls updateUsers() to replace all usersreset: false - Adds new users via createManyUsers() without removing existing usersWorkspace deletion at server/endpoints/admin.js291-320 cascades to all related data:
WorkspaceChats.delete({ workspaceId })DocumentVectors.deleteForWorkspace()Document.delete({ workspaceId })Workspace.delete({ id })VectorDb<FileRef file-url="https://github.com/Mintplex-Labs/anything-llm/blob/eaa35eba/\"delete-namespace\"" undefined file-path="\"delete-namespace\"">Hii</FileRef>This ensures complete cleanup of all workspace-related data including chat history, embeddings, and vector storage.
Sources: server/endpoints/admin.js224-320 server/endpoints/api/admin/index.js425-660 server/models/workspace.js server/models/workspaceUsers.js
Invite System Architecture
Sources: server/endpoints/admin.js158-222 server/models/invite.js
Invite creation occurs via /admin/invite/new at server/endpoints/admin.js172-202 The endpoint:
ROLES.admin or ROLES.manager permissionsimpleSSOLoginDisabledMiddleware at server/endpoints/admin.js177workspaceIds array in request bodyInvite.create() at server/endpoints/admin.js183-186The Invite.create() method:
status: 'pending'createdByUserIdinvite_workspace records for pre-assigned workspaces{ invite, error }Example request payload:
The /admin/invites endpoint at server/endpoints/admin.js158-170 returns all invites with user information via Invite.whereWithUsers(). This joins invites with creator and claimer user records to return:
Invite deactivation via /admin/invite/:id at server/endpoints/admin.js204-222 calls Invite.deactivate(id) which:
status to 'disabled'This is logged via EventLogs.logEvent("invite_deleted") at server/endpoints/admin.js211-215
When a user accepts an invite through the /accept-invite/:code page (frontend route at frontend/src/App.jsx133-135), the backend:
status: 'pending'status to 'accepted' and sets claimedByUserIdinvite_workspace tableSources: server/endpoints/admin.js158-222 server/models/invite.js server/utils/middleware/simpleSSOEnabled.js
Event Logging System Diagram
Sources: server/models/eventLogs.js server/models/telemetry.js server/endpoints/system.js1040-1077
The EventLogs model at server/models/eventLogs.js provides system-wide audit logging. Key methods:
EventLogs.logEvent(event, metadata, userId)
Creates a log entry with:
event - String event type (e.g., "user_created")metadata - JSON object with event-specific datauserId - Optional user ID who triggered the eventoccurredAt - Automatic timestampExample usage at server/endpoints/admin.js67-75:
EventLogs.whereWithData(conditions, limit, offset, orderBy)
Retrieves paginated logs with user information joined from the users table. Called by /system/event-logs endpoint at server/endpoints/system.js1040-1058
EventLogs.count()
Returns total log count for pagination calculations.
EventLogs.delete()
Clears all event logs. Used by /system/event-logs DELETE endpoint at server/endpoints/system.js1060-1077 The deletion itself is logged as an "event_logs_cleared" event.
Common event types logged throughout the system:
| Event Type | Triggered By | Metadata |
|---|---|---|
login_event | Successful login | { ip, username, multiUserMode } |
failed_login_invalid_username | Bad username | { ip, username } |
failed_login_invalid_password | Bad password | { ip, username } |
failed_login_account_suspended | Suspended account | { ip, username } |
user_created | Admin creates user | { userName, createdBy } |
user_deleted | Admin deletes user | { userName, deletedBy } |
invite_created | Admin creates invite | { inviteCode, createdBy } |
invite_deleted | Admin deactivates invite | { deletedBy } |
api_key_created | API key generation | { createdBy } |
api_key_deleted | API key deletion | { deletedBy } |
multi_user_mode_enabled | Multi-user activation | {} |
exported_chats | Chat export | { type, chatType } |
event_logs_cleared | Event log deletion | {} |
The Telemetry model at server/models/telemetry.js sends anonymous usage statistics to Mintplex Labs. Key characteristics:
Telemetry.sendTelemetry(event, properties, userId)
DISABLE_TELEMETRY=true environment variable is setTelemetry is sent for high-level events like:
Users can disable telemetry entirely via the Privacy settings UI or by setting DISABLE_TELEMETRY=true.
The admin UI displays event logs at the /settings/event-logs page (route at frontend/src/App.jsx197-199). The frontend fetches logs via:
This calls the /system/event-logs endpoint at server/endpoints/system.js1040-1058 which returns:
Administrators can clear all logs via the UI, which calls System.clearEventLogs() at frontend/src/models/system.js600-610
Sources: server/models/eventLogs.js server/models/telemetry.js server/endpoints/system.js1040-1077 frontend/src/models/system.js576-610
API Key System Architecture
Sources: server/endpoints/system.js943-1016 server/endpoints/admin.js496-559 server/models/apiKeys.js server/models/browserExtensionApiKey.js
System API keys provide programmatic access to the /v1/* API endpoints. The system supports different endpoint groups based on authentication mode:
Single-User Mode (endpoints at server/endpoints/system.js943-1016)
/system/api-keys GET - Lists all API keys/system/generate-api-key POST - Creates new API key/system/api-key/:id DELETE - Deletes specific keymultiUserMode() check at server/endpoints/system.js945-947Multi-User Mode (endpoints at server/endpoints/admin.js496-559)
/admin/api-keys GET - Lists all keys with user associations via ApiKey.whereWithUser({}) at server/endpoints/admin.js501/admin/generate-api-key POST - Creates key associated with current user at server/endpoints/admin.js522/admin/delete-api-key/:id DELETE - Removes key with event logging at server/endpoints/admin.js546ROLES.admin role via strictMultiUserRoleValid middlewareWhen creating an API key via ApiKey.create():
Single-User Mode:
Multi-User Mode:
The secret is a cryptographically random string generated using the crypto module. It's shown only once upon creation and cannot be retrieved later.
All API key operations are logged via EventLogs.logEvent():
"api_key_created" at server/endpoints/system.js973-977"api_key_deleted" at server/endpoints/system.js1005-1009The validApiKey middleware at server/utils/middleware/validApiKey.js validates API keys for programmatic endpoints:
Authorization headerApiKey model for matching secretresponse.localsThis middleware protects all /v1/* API routes including:
/v1/workspace/* - Workspace operations/v1/admin/* - Administrative functions/v1/document/* - Document managementBrowser extension keys use a separate model BrowserExtensionApiKey with additional features:
workspaceIds JSON fieldBrowserExtensionApiKey.migrateApiKeysToMultiUser() at server/endpoints/system.js556Browser extension keys are managed through the /settings/browser-extension UI (route at frontend/src/App.jsx242-246).
Sources: server/endpoints/system.js943-1016 server/endpoints/admin.js496-559 server/models/apiKeys.js server/models/browserExtensionApiKey.js server/utils/middleware/validApiKey.js
System Settings Architecture
Sources: server/models/systemSettings.js server/utils/helpers/updateENV.js server/endpoints/system.js76-91 server/endpoints/system.js472-489
The SystemSettings model at server/models/systemSettings.js manages application-level settings stored in the system_settings table. Each setting is a key-value pair:
Key methods:
SystemSettings.currentSettings()
Aggregates configuration from multiple sources:
process.envsystem_settings tableReturns a comprehensive settings object used by /setup-complete endpoint at server/endpoints/system.js83-91
SystemSettings.updateSettings(updates)
High-level update method that:
system_settings table/admin/system-preferences at server/endpoints/admin.js481-494SystemSettings._updateSettings(updates)
Internal method for direct database writes without validation hooks. Used when bypassing the standard update flow.
SystemSettings.isMultiUserMode()
Checks if multi-user mode is enabled:
Used throughout the codebase to conditionally enable multi-user features.
The updateENV() utility at server/utils/helpers/updateENV.js manages infrastructure-level configuration:
Key Features:
KEY_MAPPING - Maps friendly field names to environment variable names:
Validation - Validates values before applying (e.g., URL format, required fields)
Lifecycle Hooks - Executes pre/post-update logic:
beforeHooks - Run before setting env vars (e.g., validate credentials)afterHooks - Run after setting env vars (e.g., reset vector DB cache)Environment Persistence - In production mode, writes updates to .env file via dumpENV() at server/endpoints/system.js76-81
Example usage at server/endpoints/system.js472-489:
The /admin/system-preferences endpoint at server/endpoints/admin.js420-479 provides read access to specific application settings:
GET Request:
Supports query parameter ?labels=label1,label2,label3 to fetch specific settings. Returns:
Special handling for computed settings:
max_embed_chunk_size - Derived from embedding engine capabilitiesagent_sql_connections - Retrieved via SystemSettings.brief.agent_sql_connections()imported_agent_skills - Listed via ImportedPlugin.listImportedPlugins()feature_flags - Aggregated via SystemSettings.getFeatureFlags()POST Request:
Updates settings via SystemSettings.updateSettings() at server/endpoints/admin.js487
Enabling multi-user mode via /system/enable-multi-user at server/endpoints/system.js525-579 performs:
User.create() at server/endpoints/system.js539-543multi_user_mode: true via SystemSettings._updateSettings() at server/endpoints/system.js553-555updateENV() at server/endpoints/system.js558-563If any step fails, rollback occurs at server/endpoints/system.js570-576:
Sources: server/models/systemSettings.js server/utils/helpers/updateENV.js server/endpoints/system.js472-489 server/endpoints/system.js525-579 server/endpoints/admin.js420-494
The password recovery system allows users to regain access using recovery codes generated at first login.
Recovery Flow:
Recovery Code Generation at server/endpoints/system.js211-221
!existingUser.seen_recovery_codesgenerateRecoveryCodes(userId) from server/utils/PasswordRecovery.jsAccount Recovery via /system/recover-account at server/endpoints/system.js313-336
recoverAccount() from server/utils/PasswordRecovery.jsPassword Reset via /system/reset-password at server/endpoints/system.js338-360
resetPassword() from server/utils/PasswordRecovery.jsFrontend recovery flows handled by:
System.recoverAccount() at frontend/src/models/system.js86-103System.resetPassword() at frontend/src/models/system.js104-121Sources: server/endpoints/system.js313-360 server/utils/PasswordRecovery.js frontend/src/models/system.js86-121
The admin interface is organized in the Settings Sidebar at frontend/src/components/SettingsSidebar/index.jsx214-413 with role-based menu visibility:
Admin-Only Sections:
Manager + Admin Sections:
canViewChatHistory)Route guards enforce permissions:
AdminRoute component at frontend/src/components/PrivateRoute - Requires admin roleManagerRoute component - Requires admin or manager roleSettings pages load via lazy imports at frontend/src/App.jsx26-98 and mount in protected routes at frontend/src/App.jsx138-299
Sources: frontend/src/components/SettingsSidebar/index.jsx214-413 frontend/src/App.jsx1-312 frontend/src/components/PrivateRoute
Refresh this wiki