All authentication methods (Basic Auth, Flask-Login, OAuth) are now installed as core dependencies instead of optional extras. This simplifies setup and eliminates the need to run `uv sync --extra auth-*` when switching between authentication methods. Changes: - Move authlib, bcrypt, and flask-login to core dependencies - Remove auth-* optional dependency groups from pyproject.toml - Update documentation to remove installation instructions - Simplify troubleshooting and migration guides Benefits: - No import errors when switching auth methods - Simpler user experience - All providers available out of the box 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
9.1 KiB
TISBackup Authentication System
TISBackup provides a pluggable authentication system for securing the Flask web interface. You can choose between multiple authentication methods based on your security requirements.
Supported Authentication Methods
- None - No authentication (default, NOT recommended for production)
- Basic Auth - HTTP Basic Authentication with username/password
- Flask-Login - Session-based authentication with username/password
- OAuth2 - OAuth authentication (Google, GitHub, GitLab, or generic provider)
Quick Start
1. Choose Authentication Method
Add an [authentication]
section to /etc/tis/tisbackup_gui.ini
:
[authentication]
type = basic
username = admin
password = $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYWv.5qVQK6
use_bcrypt = True
2. Restart TISBackup
docker compose restart tisbackup_gui
Configuration Guide
Basic Authentication
Simple HTTP Basic Auth with username and password.
Pros:
- Easy to set up
- Works with all HTTP clients
- No session management needed
Cons:
- Credentials sent with every request
- No logout functionality
- Browser password prompt can be confusing
Configuration:
[authentication]
type = basic
username = admin
# Use bcrypt hash (recommended)
password = $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYWv.5qVQK6
use_bcrypt = True
realm = TISBackup Admin
Generate bcrypt hash:
python3 -c "import bcrypt; print(bcrypt.hashpw(b'yourpassword', bcrypt.gensalt()).decode())"
Docker environment:
services:
tisbackup_gui:
environment:
- TISBACKUP_SECRET_KEY=your-secret-key
# Optional: Pass credentials via env vars
# Then reference in config with ${AUTH_PASSWORD}
Flask-Login Authentication
Session-based authentication with login page and user management.
Pros:
- Clean login/logout workflow
- Session-based (no credentials in each request)
- Multiple users supported
- Password hashing with bcrypt
Cons:
- Requires custom login page
- Session management overhead
- Cookies must be enabled
Configuration:
[authentication]
type = flask-login
users_file = /etc/tis/users.txt
use_bcrypt = True
login_view = login
Create users file (/etc/tis/users.txt
):
admin:$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYWv.5qVQK6
operator:$2b$12$abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNO
viewer:$2b$12$ANOTHERBCRYPTHASHHERE1234567890ABCDEFGHIJKLMNOPQRS
Generate user entry:
USERNAME="admin"
PASSWORD="yourpassword"
HASH=$(python3 -c "import bcrypt; print(bcrypt.hashpw(b'$PASSWORD', bcrypt.gensalt()).decode())")
echo "$USERNAME:$HASH" >> /etc/tis/users.txt
Permissions:
chmod 600 /etc/tis/users.txt
chown root:root /etc/tis/users.txt
OAuth2 Authentication
Delegate authentication to external OAuth providers (Google, GitHub, GitLab, etc.)
Pros:
- No password management
- Leverage existing identity providers
- Support for SSO
- Can restrict by domain or specific users
Cons:
- Requires OAuth app registration
- Internet connectivity required
- More complex setup
- External dependency
Google OAuth
Setup:
- Go to Google Cloud Console
- Create OAuth 2.0 Client ID
- Add authorized redirect URI:
http://your-server:8080/oauth/callback
- Note the Client ID and Client Secret
Configuration:
[authentication]
type = oauth
provider = google
client_id = 123456789-abcdefghijklmnop.apps.googleusercontent.com
client_secret = GOCSPX-your-client-secret-here
redirect_uri = http://your-server:8080/oauth/callback
# Restrict to specific domain(s)
authorized_domains = example.com,mycompany.com
# Or restrict to specific users
authorized_users = admin@example.com,backup-admin@example.com
GitHub OAuth
Setup:
- Go to GitHub Settings > Developer settings > OAuth Apps
- Register a new application
- Set Authorization callback URL:
http://your-server:8080/oauth/callback
- Note the Client ID and Client Secret
Configuration:
[authentication]
type = oauth
provider = github
client_id = your-github-client-id
client_secret = your-github-client-secret
redirect_uri = http://your-server:8080/oauth/callback
authorized_users = admin@example.com,devops@example.com
GitLab OAuth
Setup:
- Go to GitLab User Settings > Applications
- Create application with scopes:
read_user
,email
- Set Redirect URI:
http://your-server:8080/oauth/callback
- Note the Application ID and Secret
Configuration:
[authentication]
type = oauth
provider = gitlab
client_id = your-gitlab-application-id
client_secret = your-gitlab-secret
redirect_uri = http://your-server:8080/oauth/callback
authorized_domains = example.com
Generic OAuth Provider
For custom OAuth providers:
[authentication]
type = oauth
provider = generic
client_id = your-client-id
client_secret = your-client-secret
redirect_uri = http://your-server:8080/oauth/callback
# Custom endpoints
authorization_endpoint = https://auth.example.com/oauth/authorize
token_endpoint = https://auth.example.com/oauth/token
userinfo_endpoint = https://auth.example.com/oauth/userinfo
scopes = openid,email,profile
# Authorization rules
authorized_domains = example.com
Security Best Practices
1. Use HTTPS in Production
Always use a reverse proxy with TLS:
server {
listen 443 ssl http2;
server_name tisbackup.example.com;
ssl_certificate /etc/letsencrypt/live/tisbackup.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/tisbackup.example.com/privkey.pem;
location / {
proxy_pass http://localhost:8080/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
2. Set Strong Flask Secret Key
# Generate secret
python3 -c "import secrets; print(secrets.token_hex(32))"
# Set in environment
export TISBACKUP_SECRET_KEY=your-generated-secret-key
3. Protect Configuration Files
chmod 600 /etc/tis/tisbackup_gui.ini
chmod 600 /etc/tis/users.txt # if using Flask-Login
chown root:root /etc/tis/*.ini
4. Use Environment Variables for Secrets
Instead of hardcoding secrets in config files:
[authentication]
type = oauth
client_id = ${OAUTH_CLIENT_ID}
client_secret = ${OAUTH_CLIENT_SECRET}
Then set in Docker Compose:
services:
tisbackup_gui:
environment:
- OAUTH_CLIENT_ID=your-client-id
- OAUTH_CLIENT_SECRET=your-client-secret
- TISBACKUP_SECRET_KEY=your-secret-key
5. Regularly Rotate Credentials
- Change passwords/secrets every 90 days
- Rotate OAuth client secrets annually
- Review authorized users/domains regularly
6. Monitor Authentication Logs
Check logs for failed authentication attempts:
docker logs tisbackup_gui | grep -i "auth"
Troubleshooting
Basic Auth Not Working
-
Verify password hash:
python3 -c "import bcrypt; print(bcrypt.checkpw(b'yourpassword', b'$2b$12$your-hash'))"
-
Check browser credentials:
- Clear browser cache
- Try incognito/private mode
Flask-Login Issues
-
Users file not found:
ls -la /etc/tis/users.txt chmod 600 /etc/tis/users.txt
-
Session problems:
- Check
TISBACKUP_SECRET_KEY
is set - Ensure cookies are enabled
- Check
OAuth Problems
-
Redirect URI mismatch:
- Ensure redirect URI in config matches OAuth app settings exactly
- Check for http vs https mismatch
-
Unauthorized domain/user:
- Verify email matches
authorized_users
or domain matchesauthorized_domains
- Check OAuth provider returns email in user info
- Verify email matches
-
Token errors:
- Verify client ID and secret are correct
- Check OAuth app is enabled
- Ensure scopes are correct
API Access with Authentication
Basic Auth
curl -u admin:password http://localhost:8080/api/backups
OAuth (with access token)
# Not recommended for API access - use service account or API keys instead
Recommendation for API Access
For programmatic API access, use Basic Auth with a dedicated API user:
[authentication]
type = basic
username = api-user
password = $2b$12$...
Or implement API key authentication separately for API endpoints.
Migration Guide
From No Auth to Basic Auth
- Add authentication section to config
- Restart service
- Update client scripts with credentials
From Basic Auth to OAuth
- Register OAuth application
- Update configuration
- Test OAuth login flow
- Update redirect URI if needed
From Flask-Login to OAuth
- Register OAuth application
- Map user emails to OAuth provider
- Update configuration
- Test migration with test users first
Support
For issues or questions:
- Check logs:
docker logs tisbackup_gui
- Review configuration syntax
- Verify dependencies are installed
- See SECURITY_IMPROVEMENTS.md for security context