VLog supports multi-user authentication with role-based access control (RBAC). This replaces the legacy single admin secret with proper user accounts, sessions, and API keys.
- User accounts with username/email and password authentication
- Role-based access control (Admin, Editor, Viewer)
- Session-based browser auth with HTTP-only cookies
- API keys for programmatic access
- OIDC integration for self-hosted identity providers
- Invite-only registration (configurable)
| Role | Description | Key Permissions |
|---|---|---|
| Admin | Full system access | All permissions including user management |
| Editor | Content creator | Upload, edit/delete own videos, view own analytics |
| Viewer | Read-only access | Browse and watch videos (for private instances) |
| Permission | Admin | Editor | Viewer |
|---|---|---|---|
| View videos | ✅ | ✅ | ✅ |
| Upload videos | ✅ | ✅ | ❌ |
| Edit own videos | ✅ | ✅ | ❌ |
| Edit any video | ✅ | ❌ | ❌ |
| Delete own videos | ✅ | ✅ | ❌ |
| Delete any video | ✅ | ❌ | ❌ |
| Manage categories/tags | ✅ | ❌ | ❌ |
| View all analytics | ✅ | ❌ | ❌ |
| View own analytics | ✅ | ✅ | ❌ |
| Manage users | ✅ | ❌ | ❌ |
| Manage workers | ✅ | ❌ | ❌ |
| System settings | ✅ | ❌ | ❌ |
# REQUIRED: Session secret for signing tokens
# Generate with: openssl rand -base64 32
VLOG_SESSION_SECRET_KEY=your-secret-key-here
# Session expiry (optional, defaults shown)
VLOG_SESSION_EXPIRY_HOURS=24
VLOG_REFRESH_EXPIRY_DAYS=7
# Registration mode (optional)
# invite - Users must be invited by admin (default)
# open - Anyone can register (not recommended for private instances)
# disabled - No new registrations
VLOG_REGISTRATION_MODE=inviteFor integrating with self-hosted identity providers (Keycloak, Authentik, Authelia, Zitadel, etc.):
VLOG_OIDC_ENABLED=true
VLOG_OIDC_PROVIDER_NAME=SSO # Button text: "Sign in with SSO"
VLOG_OIDC_DISCOVERY_URL=https://keycloak.example.com/realms/vlog/.well-known/openid-configuration
VLOG_OIDC_CLIENT_ID=vlog
VLOG_OIDC_CLIENT_SECRET=your-client-secret
VLOG_OIDC_SCOPES=openid,profile,email # Standard OIDC scopes
VLOG_OIDC_AUTO_CREATE_USERS=false # Auto-provision users on first login
VLOG_OIDC_DEFAULT_ROLE=viewer # Role for auto-created users
VLOG_OIDC_TIMEOUT_SECONDS=10 # Request timeoutThese settings are configured via environment variables:
| Variable | Default | Description |
|---|---|---|
VLOG_PASSWORD_MIN_LENGTH |
12 | Minimum password length |
VLOG_LOCKOUT_THRESHOLD |
5 | Failed login attempts before lockout |
VLOG_LOCKOUT_DURATION_MINUTES |
30 | Account lockout duration |
VLOG_MAX_SESSIONS_PER_USER |
10 | Maximum concurrent sessions |
POST /api/v1/auth/login
Content-Type: application/json
{
"username_or_email": "user@example.com",
"password": "your-password"
}Response (success):
{
"user_id": "uuid",
"username": "johndoe",
"email": "user@example.com",
"display_name": "John Doe",
"role": "editor",
"expires_at": "2024-01-16T10:30:00Z"
}Response (failure):
{
"success": false,
"message": "Invalid credentials"
}GET /api/v1/auth/checkResponse:
{
"authenticated": true,
"auth_required": true,
"auth_mode": "user",
"oidc_enabled": false,
"oidc_provider_name": null,
"user": { ... }
}POST /api/v1/auth/logoutPOST /api/v1/auth/refreshReturns new session tokens. Used for token rotation.
GET /api/v1/auth/mePUT /api/v1/auth/me
Content-Type: application/json
{
"display_name": "New Name",
"avatar_url": "https://example.com/avatar.jpg"
}Note: Email cannot be changed via this endpoint. Contact an admin to update your email.
POST /api/v1/auth/password
Content-Type: application/json
{
"current_password": "old-password",
"new_password": "new-secure-password"
}POST /api/v1/auth/forgot
Content-Type: application/json
{
"email": "user@example.com"
}Always returns success (prevents user enumeration).
POST /api/v1/auth/reset
Content-Type: application/json
{
"token": "reset-token-from-email",
"new_password": "new-secure-password"
}GET /api/v1/auth/sessionsResponse:
{
"sessions": [
{
"id": "session-uuid",
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0...",
"created_at": "2024-01-15T10:30:00Z",
"is_current": true
}
]
}DELETE /api/v1/auth/sessions/{session_id}GET /api/v1/usersQuery parameters:
| Parameter | Type | Description |
|---|---|---|
| limit | int | Max items (default: 50) |
| offset | int | Pagination offset |
| role | string | Filter by role |
| status | string | Filter by status (active, disabled, pending) |
| search | string | Search username/email |
POST /api/v1/users
Content-Type: application/json
{
"username": "newuser",
"email": "newuser@example.com",
"password": "secure-password",
"display_name": "New User",
"role": "editor"
}PUT /api/v1/users/{user_id}
Content-Type: application/json
{
"role": "admin",
"display_name": "Updated Name"
}DELETE /api/v1/users/{user_id}Soft-deletes (disables) the user account.
POST /api/v1/users/{user_id}/reset-passwordGET /api/v1/api-keysPOST /api/v1/api-keys
Content-Type: application/json
{
"name": "CI/CD Pipeline",
"expires_in_days": 90
}Response (key shown only once):
{
"id": "key-uuid",
"name": "CI/CD Pipeline",
"key": "vlog_ak_xxxxxxxxxxxxx",
"key_prefix": "vlog_ak_",
"expires_at": "2024-04-15T10:30:00Z",
"created_at": "2024-01-15T10:30:00Z"
}DELETE /api/v1/api-keys/{key_id}GET /api/v1/invitesPOST /api/v1/invites
Content-Type: application/json
{
"email": "newuser@example.com",
"role": "editor",
"expires_in_days": 7
}Response:
{
"id": "invite-uuid",
"email": "newuser@example.com",
"role": "editor",
"token": "abc123...",
"invite_url": "/accept-invite?token=abc123...",
"expires_at": "2024-01-22T10:30:00Z"
}Note: The invite_url is a relative path. Prepend your server's base URL when sharing with users.
DELETE /api/v1/invites/{invite_id}API keys can be used for programmatic access instead of session cookies.
GET /api/v1/videos
Authorization: Bearer vlog_ak_xxxxxxxxxxxxxAPI keys inherit permissions from the user's role. A key created by an editor has editor-level access.
When VLog starts with no users in the database, it enters setup mode. The setup wizard allows you to create the first admin account.
-
Check Setup Status
- Navigate to the admin UI or call
GET /api/v1/auth/setup - If no users exist, you'll see the setup wizard
- Navigate to the admin UI or call
-
Create Admin Account
- Provide username, email, password (min 12 characters), and display name
- The first user is automatically assigned the
adminrole - You'll be logged in automatically after creation
-
Configure Registration Mode
- Set
VLOG_REGISTRATION_MODEto control how new users join:invite(default) - Users must be invited by adminopen- Anyone can register (not recommended for private instances)disabled- No new registrations
- Set
# Check if setup is needed
curl http://localhost:9001/api/v1/auth/setup
# Create initial admin
curl -X POST http://localhost:9001/api/v1/auth/setup \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"email": "admin@example.com",
"password": "secure-password-12chars",
"display_name": "Administrator"
}'If you're upgrading from an older VLog version that used VLOG_ADMIN_API_SECRET:
export VLOG_SESSION_SECRET_KEY=$(openssl rand -base64 32)On first access to the admin UI (or via API), you'll be prompted to create an admin account. This replaces the legacy single-admin authentication.
After creating your admin account, remove VLOG_ADMIN_API_SECRET from your environment. The legacy authentication will continue to work for backwards compatibility but is deprecated.
- Minimum 12 characters
- Must contain letters and numbers/symbols
- Argon2id hashing (memory-hard, GPU-resistant)
- Account lockout after 5 failed attempts
- Lockout duration: 30 minutes (configurable)
- Rate limiting on login endpoint
- HTTP-only, Secure, SameSite=Lax cookies
- 24-hour session expiry (configurable)
- 7-day refresh token expiry
- Refresh token rotation with theft detection
- Maximum 10 concurrent sessions per user
- State parameter for CSRF protection
- Nonce validation for replay protection
- Circuit breaker for provider failures
VLog supports any OIDC-compliant identity provider.
- Keycloak
- Authentik
- Authelia
- Zitadel
- Google (configured as OIDC)
- Microsoft Entra ID
- Any standard OIDC provider
- Create a new client in your identity provider
- Configure the callback URL:
https://your-vlog.com/api/v1/auth/oidc/callback - Set the environment variables (see Configuration section)
- Restart VLog
When a user logs in via OIDC:
-
If
VLOG_OIDC_AUTO_CREATE_USERS=true:- A new user account is created
- The OIDC connection is linked
- User gets the default role
-
If
VLOG_OIDC_AUTO_CREATE_USERS=false:- Admin must create the user first
- User links their OIDC account on first login
Existing users can link their OIDC account:
POST /api/v1/auth/oidc/linkAnd unlink:
DELETE /api/v1/auth/oidcThe session secret must be set in production. Generate one:
openssl rand -base64 32Wait for the lockout period to expire, or have an admin reset the password.
- Check the discovery URL is accessible
- Verify client ID and secret
- Ensure callback URL matches exactly
- Check provider logs for errors
Sessions expire after 24 hours. Use the refresh endpoint or re-login.
- Verify the key hasn't been revoked
- Check if it has expired
- Ensure proper Authorization header format
- API.md - API endpoint reference including auth endpoints
- CONFIGURATION.md - Authentication environment variables
- DEPLOYMENT.md - Production auth setup and nginx configuration
- DATABASE.md - User and session table schemas