This document describes AnythingLLM's authentication architecture, covering the four authentication modes and JWT token management. The system supports both single-user and multi-user deployments with flexible authentication mechanisms.
For role-based access control and user management, see Multi-User Management. For API endpoint documentation, see API Authentication and Overview.
AnythingLLM implements four authentication methods that can be used independently or in combination:
process.env.AUTH_TOKEN)JWT_EXPIRY)ApiKey model)TemporaryAuthToken model)The authentication system adapts between single-user mode (password-only protection with no user accounts) and multi-user mode (full user management with roles and permissions). The mode is determined by SystemSettings.isMultiUserMode() queried via the multiUserMode(response) utility at server/utils/http.js30-44
All authentication routes are registered in the systemEndpoints(app) function at server/endpoints/system.js65 with core utilities in server/utils/http.js including makeJWT(), userFromSession(), and multiUserMode().
Password Security: All passwords are hashed using bcrypt with 10 salt rounds via bcrypt.hashSync(password, 10) before storage. Password validation uses bcrypt.compareSync(plainPassword, hashedPassword).
Authentication Flow Architecture
Sources: server/endpoints/system.js65-311 server/utils/http.js7-72 server/utils/middleware/validatedRequest.js server/utils/middleware/validApiKey.js server/utils/middleware/simpleSSOEnabled.js server/models/temporaryAuthToken.js server/models/apiKeys.js
The primary authentication mechanism uses JSON Web Tokens (JWT) for session management. Tokens are signed using process.env.JWT_SECRET and have a configurable expiry (default 30 days via process.env.JWT_EXPIRY).
Token Lifecycle:
makeJWT(payload, expiryTime) at server/utils/http.js7-23 creates signed tokens using jsonwebtoken.sign()/request-token endpoint at server/endpoints/system.js183-334 issues tokens after credential validation/system/check-token endpoint at server/endpoints/system.js113-135 verifies token validityuserFromSession(request, response) at server/utils/http.js48-72 decodes tokens from the Authorization: Bearer <token> headerlocalStorage.getItem(AUTH_TOKEN) with periodic validation via System.checkAuth() at frontend/src/models/system.js88-97JWT Token Generation and Validation Flow
Sources: server/endpoints/system.js183-334 server/endpoints/system.js113-135 server/utils/http.js7-23 server/utils/http.js30-46 server/utils/http.js48-72 server/models/user.js server/models/eventLogs.js frontend/src/models/system.js88-97
API keys provide programmatic access to AnythingLLM's REST API for developers and integrations. They are managed through the ApiKey model at server/models/apiKeys.js and validated by the validApiKey middleware at server/utils/middleware/validApiKey.js
API keys are stored in the database with hashed secrets and associated with user accounts in multi-user mode. In single-user mode, API keys are system-wide without user association.
API Key Validation Flow
API Key Management Endpoints
| Endpoint | Method | Access | Purpose |
|---|---|---|---|
/system/api-keys | GET | Single-user only | List all API keys via ApiKey.where({}) |
/system/generate-api-key | POST | Single-user only | Generate new API key via ApiKey.create() |
/system/api-key/:id | DELETE | Single-user only | Revoke API key via ApiKey.delete({id}) |
In multi-user mode, API key management is handled through admin endpoints at /admin/api-keys, /admin/generate-api-key, and /admin/delete-api-key/:id with admin-only access control.
Sources: server/utils/middleware/validApiKey.js server/models/apiKeys.js server/endpoints/system.js892-965 server/endpoints/admin.js496-559 server/endpoints/api/admin/index.js12 server/endpoints/api/workspace/index.js15
AnythingLLM supports Single Sign-On via the Simple SSO mechanism using temporary authentication tokens. This allows external authentication providers to generate time-limited tokens that users can exchange for full session tokens.
Simple SSO Flow
The Simple SSO system uses the TemporaryAuthToken model at server/models/temporaryAuthToken.js to issue and validate temporary tokens. The simpleSSOEnabled middleware at server/utils/middleware/simpleSSOEnabled.js8-25 checks if SSO is enabled before allowing SSO authentication. Additionally, simpleSSOLoginDisabled middleware at server/utils/middleware/simpleSSOEnabled.js27-42 can be used to block credential-based login when SSO is the primary authentication method.
SSO Configuration
SSO can be disabled via the simpleSSOLoginDisabled check at server/endpoints/system.js122-131 which prevents traditional username/password login when SSO is enforced. This is controlled by the SIMPLE_SSO_LOGIN_DISABLED environment variable.
Sources: server/endpoints/system.js270-311 server/utils/middleware/simpleSSOEnabled.js8-42 server/models/temporaryAuthToken.js server/endpoints/system.js122-131 frontend/src/pages/Login/SSO/simple.jsx
Session-based authentication manages user sessions through JWT tokens with support for session refresh and automatic logout on suspension. The system uses both server-side validation and client-side session management.
Session Validation and Refresh Architecture
Session Management Implementation:
Server-Side Validation via userFromSession() at server/utils/http.js48-72:
Authorization: Bearer <token> headerjsonwebtoken.verify(token, process.env.JWT_SECRET)User.get({id: decoded.id})nullFrontend Session State via AuthContext at frontend/src/AuthContext.jsx12-79:
localStorage.getItem(AUTH_USER)localStorage.getItem(AUTH_TOKEN)useEffect at frontend/src/AuthContext.jsx50-72System.refreshUser() at frontend/src/models/system.js116-127Session Expiry:
process.env.JWT_EXPIRY (default: "30d")/system/check-token at server/endpoints/system.js113-135System.needsAuthCheck() at frontend/src/models/system.js81-86 (every 5 minutes)AuthContext useEffect at frontend/src/AuthContext.jsx50-72User Refresh Endpoint at server/endpoints/system.js143-181:
if (user.suspended) return {success: false, message: 'User is suspended.'}User.filterFields(user)Sources: server/utils/http.js48-72 server/endpoints/system.js113-135 server/endpoints/system.js143-181 frontend/src/AuthContext.jsx12-79 frontend/src/models/system.js81-127 server/utils/middleware/validatedRequest.js8-41
The core authentication endpoints handle login, token validation, account recovery, and mode transitions. These are registered in systemEndpoints(app) at server/endpoints/system.js65
| Endpoint | Method | Purpose | Middleware | Handler Location |
|---|---|---|---|---|
/request-token | POST | Username/password or simple password login | None | system.js117-268 |
/request-token/sso/simple | GET | SSO login via temporary token | simpleSSOEnabled | system.js270-311 |
/system/check-token | GET | Validate JWT token | validatedRequest | system.js93-115 |
/system/recover-account | POST | Account recovery via recovery codes | isMultiUserSetup | system.js313-336 |
/system/reset-password | POST | Password reset with reset token | isMultiUserSetup | system.js338-360 |
/system/update-password | POST | Update system password (single-user) | validatedRequest | system.js491-523 |
/system/enable-multi-user | POST | Transition to multi-user mode | validatedRequest | system.js525-579 |
/system/multi-user-mode | GET | Check authentication mode | None | system.js581-589 |
Authentication Route Organization
Sources: server/endpoints/system.js93-589
AnythingLLM operates in two distinct authentication modes determined by SystemSettings.isMultiUserMode() and checked via the multiUserMode(response) utility function at server/utils/http.js30-44
In single-user mode, authentication uses a single system password stored in the AUTH_TOKEN environment variable. No user accounts or roles exist in this mode.
Single-User Authentication Implementation
The single-user authentication logic at server/endpoints/system.js230-263:
multiUserMode(response) returns false via SystemSettings.isMultiUserMode()process.env.AUTH_TOKEN using bcrypt.compareSync(password, bcrypt.hashSync(process.env.AUTH_TOKEN, 10))new EncryptionManager().encrypt(password)makeJWT({p: encryptedPassword}, process.env.JWT_EXPIRY) (30 days)EventLogs.logEvent('login_event', {multiUserMode: false})Sources: server/endpoints/system.js230-263 server/utils/http.js30-44 server/utils/EncryptionManager.js server/models/eventLogs.js
Multi-user mode implements full user account management with the User model at server/models/user.js role-based access control via ROLES constant at server/utils/middleware/multiUserProtected.js7 and individual user sessions with recovery codes.
Multi-User Authentication Flow
Multi-user authentication at server/endpoints/system.js121-229:
multiUserMode(response) returns truesimpleSSOLoginDisabled()User._get({username: String(username)})bcrypt.compareSync(String(password), existingUser.password)existingUser.suspended flagmakeJWT({id: existingUser.id, username: existingUser.username}, process.env.JWT_EXPIRY)!existingUser.seen_recovery_codes), generates codes via generateRecoveryCodes(existingUser.id)EventLogs.logEvent('login_event', {ip, username}, existingUser.id)Multi-User Mode Transition
The /system/enable-multi-user endpoint at server/endpoints/system.js525-579 handles the transition:
Transition steps:
response.locals.multiUserMode to prevent duplicate transitionUser.create({username, password, role: ROLES.admin})SystemSettings._updateSettings({multi_user_mode: true})BrowserExtensionApiKey.migrateApiKeysToMultiUser(user.id)updateENV({JWTSecret: process.env.JWT_SECRET || v4()}, true)EventLogs.logEvent('multi_user_mode_enabled', {}, user.id)Sources: server/endpoints/system.js121-232 server/endpoints/system.js525-579 server/models/user.js server/utils/middleware/multiUserProtected.js7 server/utils/PasswordRecovery/index.js server/models/browserExtensionApiKey.js
The system implements comprehensive password management with bcrypt hashing, recovery codes for multi-user accounts, and password reset capabilities.
Password Hashing and Storage
All passwords are hashed using bcrypt before storage:
bcrypt.hashSync(password, 10) creates salted hash with 10 roundsbcrypt.compareSync(plainPassword, hashedPassword) verifies credentialsusers.password column (multi-user) or process.env.AUTH_TOKEN (single-user)Recovery Codes System
Multi-user accounts receive 10 recovery codes on first login for account recovery:
Generation via generateRecoveryCodes(userId) at server/utils/PasswordRecovery/index.js:
crypto.randomBytes(3).toString('hex')RecoveryCodes.createMany(user.id, hashedCodes)User.update(id, {seen_recovery_codes: true})First Login Flow at server/endpoints/system.js277-287:
Password Recovery and Reset Flow
Password Management Endpoints
| Endpoint | Mode | Purpose | Implementation |
|---|---|---|---|
/system/recover-account | Multi-user | Validate recovery codes, issue reset token | system.js379-402 calls recoverAccount(username, recoveryCodes) |
/system/reset-password | Multi-user | Reset password using reset token | system.js404-426 calls resetPassword(token, newPassword, confirmPassword) |
/system/update-password | Single-user | Update instance password | system.js557-589 calls updateENV({AuthToken, JWTSecret}) |
Single-User Password Update at server/endpoints/system.js557-589:
process.env.AUTH_TOKEN via updateENV({AuthToken: newPassword, JWTSecret: v4()}, true)usePassword: falseSources: server/endpoints/system.js277-287 server/endpoints/system.js379-426 server/endpoints/system.js557-589 server/utils/PasswordRecovery/index.js server/models/recoveryCodes.js server/models/user.js frontend/src/models/system.js128-163
The system implements role-based access control through middleware functions that check user permissions. Role definitions are in the ROLES constant at server/utils/middleware/multiUserProtected.js7-11
The system uses three main middleware functions for role enforcement:
Middleware Architecture
Role Validation Middleware Functions
validatedRequest at server/utils/middleware/validatedRequest.js8:
userFromSession(request, response)response.locals.userflexUserRoleValid(allowedRoles) at server/utils/middleware/multiUserProtected.js78:
user.role matches any allowedRoles or if ROLES.all is includedflexUserRoleValid([ROLES.admin, ROLES.manager])strictMultiUserRoleValid(allowedRoles) at server/utils/middleware/multiUserProtected.js130:
isMultiUserSetup(response) to be trueuser.role matches allowedRolesstrictMultiUserRoleValid([ROLES.admin])Role Validation Implementation Example
Common middleware usage patterns in system endpoints:
[validatedRequest] - Any authenticated user at system.js93[validatedRequest, flexUserRoleValid([ROLES.admin])] - Admin only at system.js474[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])] - Admin or Manager at system.js364[validatedRequest, flexUserRoleValid([ROLES.all])] - Any authenticated user with role check at system.js670Sources: server/utils/middleware/multiUserProtected.js7-162 server/utils/middleware/validatedRequest.js8-41 server/endpoints/system.js93-1248 server/endpoints/admin.js35-47
AnythingLLM provides comprehensive API documentation through Swagger/OpenAPI integration accessible at /api/docs.
The API follows RESTful conventions with versioned endpoints under the /api/v1 prefix:
/v1/auth/v1/admin/*/v1/workspace/*/v1/document/*/v1/system/*OpenAPI Documentation Structure
The OpenAPI specification includes detailed schemas, request/response examples, and authentication requirements for each endpoint.
Sources: server/swagger/openapi.json1-100 server/endpoints/api/workspace/index.js22-101 server/endpoints/api/document/index.js26-136
Refresh this wiki