LDAP/Active Directory Authentication
Overview
OpenTranscribe supports hybrid authentication combining LDAP/Active Directory with local database users:
- LDAP users: Auto-created on first login with role based on
LDAP_ADMIN_USERS - Local admin users: Created manually via registration endpoint with database passwords
- Flexible auth: System supports both email-based (local) and username-based (LDAP) login — users can log in with their sAMAccountName, uid, or any configured username attribute
- Priority: Local users checked first when
auth_type='local'in database
v0.4.0 Change: LDAP configuration is now managed via the Super Admin UI (Settings → Authentication → LDAP/Active Directory). Settings are stored encrypted (AES-256-GCM) in the database. Environment variables (
LDAP_SERVER,LDAP_BASE_DN, etc.) continue to work as an initial seed fallback but database configuration takes precedence once saved.
Configuration
Primary Method: Super Admin UI (v0.4.0+)
Configure LDAP via the Admin UI for immediate, encrypted, restart-free configuration:
- Log in as super_admin (
admin@example.com) - Navigate to Settings → Authentication → LDAP/Active Directory
- Click "Edit" and fill in all fields (see table in SUPER_ADMIN_GUIDE.md)
- Click "Test Connection" to verify before saving
- Click "Save Configuration"
Settings saved via the UI are encrypted with AES-256-GCM and take effect immediately.
Environment Variables (Fallback / Initial Seed)
These variables are used only when no database configuration exists for LDAP. Once configuration is saved via the Admin UI, these env vars are ignored.
Add the following to your .env file:
# Enable LDAP authentication
LDAP_ENABLED=true
# LDAP/AD Server
LDAP_SERVER=ldaps://your-ad-server.domain.com
LDAP_PORT=636
LDAP_USE_SSL=true
LDAP_USE_TLS=false
# Service account for LDAP search (read-only user)
LDAP_BIND_DN=CN=service-account,CN=Users,DC=domain,DC=com
LDAP_BIND_PASSWORD=your-service-account-password
# Search base and filter
LDAP_SEARCH_BASE=DC=domain,DC=com
LDAP_USERNAME_ATTR=sAMAccountName # Username attribute (sAMAccountName, uid, etc.)
LDAP_USER_SEARCH_FILTER=({username_attr}={username}) # Uses LDAP_USERNAME_ATTR
# User attributes
LDAP_EMAIL_ATTR=mail
LDAP_NAME_ATTR=cn
# Timeout (seconds)
LDAP_TIMEOUT=10
# Optional: Comma-separated list of AD usernames that should be admins
LDAP_ADMIN_USERS=admin1,admin2,john.doe
Configuration Details
- LDAP_SERVER: Full LDAP URL (ldaps:// for secure LDAP)
- LDAP_PORT: 389 for standard LDAP, 636 for LDAPS
- LDAP_USE_SSL: Enable LDAPS (recommended for production)
- LDAP_USE_TLS: Alternative to LDAPS (StartTLS)
- LDAP_BIND_DN: Distinguished Name of service account (must have read access to user objects)
- LDAP_BIND_PASSWORD: Password for service account (stored in .env)
- LDAP_SEARCH_BASE: Base DN for user searches (e.g., DC=domain,DC=com)
- LDAP_USERNAME_ATTR: Username attribute for user search (default:
sAMAccountName)- Active Directory:
sAMAccountName - OpenLDAP:
uid
- Active Directory:
- LDAP_USER_SEARCH_FILTER: Filter to find users by username
- Format:
({username_attr}={username})where{username_attr}is replaced byLDAP_USERNAME_ATTR - Active Directory:
(sAMAccountName={username}) - OpenLDAP:
(uid={username})
- Format:
- LDAP_EMAIL_ATTR: Attribute containing user email (mail, userPrincipalName, etc.)
- LDAP_NAME_ATTR: Attribute containing full name (cn, displayName, etc.)
- LDAP_ADMIN_USERS: List of AD usernames that should automatically be admins
Username Attribute Configuration
The LDAP_USERNAME_ATTR setting provides flexibility for different directory services:
Active Directory (default):
LDAP_USERNAME_ATTR=sAMAccountName
LDAP_USER_SEARCH_FILTER=(sAMAccountName={username})
OpenLDAP:
LDAP_USERNAME_ATTR=uid
LDAP_USER_SEARCH_FILTER=(uid={username})
Custom Attribute:
LDAP_USERNAME_ATTR=employeeId
LDAP_USER_SEARCH_FILTER=(employeeId={username})
The system automatically replaces {username_attr} in LDAP_USER_SEARCH_FILTER with the value of LDAP_USERNAME_ATTR, allowing consistent filter configuration across different directory services.
Authentication Flow
Hybrid Authentication Strategy
The system uses a flexible authentication flow based on the user's auth_type in the database:
1. Local User (Database Password)
User exists in DB + auth_type = 'local'
→ Try direct database authentication (bypasses ORM for reliability)
→ If direct fails, try ORM authentication
→ Success: Return JWT token
→ Failure: Try LDAP (as fallback if user exists)
2. LDAP User
LDAP Enabled OR user not found locally
→ Bind to AD with service account
→ Search for user by LDAP_USERNAME_ATTR (or email if username contains @)
→ If not found by username, try search by email address
→ Extract email, username, and cn attributes
→ Bind as user to verify password
→ Create/update user in database
→ Return JWT token
3. First-Time LDAP Login
User not in database
→ Authenticate via LDAP
→ Create user record:
- email: from AD
- full_name: from AD
- ldap_uid: sAMAccountName
- auth_type: 'ldap'
- role: 'admin' if in LDAP_ADMIN_USERS else 'user'
→ Return JWT token
Login Input Options
Users can login with:
- Email address (for local users, also supported for LDAP users)
- Username/sAMAccountName (for LDAP users)
The system automatically handles both formats:
# Local user login (email-based)
curl -X POST http://localhost:5174/api/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin@example.com&password=local_password"
# LDAP user login (username-based)
curl -X POST http://localhost:5174/api/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=john.doe&password=ad_password"
# LDAP user login (email-based - extracts username before @)
curl -X POST http://localhost:5174/api/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=john.doe@example.com&password=ad_password"
Security Features
LDAP Injection Protection
The system escapes special characters in LDAP filter values to prevent injection attacks:
_escaped_username = _escape_ldap_filter(username)
# Escapes: ( ) * \ NUL characters
SSL/TLS
- LDAPS (LDAP over SSL) is recommended for production
- Use port 636 with
LDAP_USE_SSL=true - Ensure valid SSL certificate on AD server
- Test connection:
openssl s_client -connect ad-server:636
Password Change Restrictions
- LDAP users cannot change passwords in OpenTranscribe — changes must be done in AD/LDAP
- Local users only can change their password via the UI or API
Deployment
Development/Testing with LDAP Test Container
# Start OpenTranscribe with LDAP test container
./opentr.sh start dev --with-ldap-test
Test Container Details:
- LDAP server:
localhost:3890 - Web UI:
http://localhost:17170 - Admin credentials:
admin/admin_password - Base DN:
dc=example,dc=com
Production Deployment with Active Directory
- Log in as super_admin
- Go to Settings → Authentication → LDAP/Active Directory
- Configure with your AD settings and click "Test Connection"
- Click "Save Configuration" — changes take effect immediately
Troubleshooting
Common Errors
- "Failed to bind to LDAP server" — Check LDAP_SERVER, LDAP_PORT, and service account credentials
- "User not found in LDAP" — Verify LDAP_SEARCH_BASE and LDAP_USER_SEARCH_FILTER
- "User has no email attribute" — Verify LDAP_EMAIL_ATTR is populated in AD
- "Authentication failed: user is LDAP type, cannot use password auth" — User has
auth_type='ldap'; use LDAP credentials, not local password - "Password change not allowed for LDAP users" — Change password in AD/LDAP directory directly
Production Checklist
- LDAPS enabled with valid SSL certificate
- Read-only service account created
- LDAP config saved via Super Admin UI (Settings → Authentication → LDAP/AD)
-
LDAP_ADMIN_USERSconfigured for admins -
LDAP_USERNAME_ATTRconfigured correctly for your directory - Firewall allows outbound LDAP connections from backend container
- Test authentication with real AD users (username-based and email-based)
- Verify LDAP users cannot change passwords in UI or API