9.0 KiB
Player Authentication System - DigiServer v2 & Kiwy-Signage
Overview
DigiServer v2 now includes a secure player authentication system compatible with Kiwy-Signage players. Players can authenticate using either a password or quick connect code, and their credentials are securely stored locally.
Features
✅ Dual Authentication Methods
- Password-based authentication (secure bcrypt hashing)
- Quick Connect codes for easy pairing
✅ Secure Credential Storage
- Auth codes saved locally in encrypted configuration
- No need to re-authenticate on every restart
✅ Automatic Session Management
- Auth codes persist across player restarts
- Automatic status updates and heartbeats
✅ Player Identification
- Unique hostname for each player
- Configurable display orientation (Landscape/Portrait)
Database Schema
The Player model now includes:
class Player(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
hostname = db.Column(db.String(255), unique=True, nullable=False, index=True)
location = db.Column(db.String(255), nullable=True)
auth_code = db.Column(db.String(255), unique=True, nullable=False, index=True)
password_hash = db.Column(db.String(255), nullable=False)
quickconnect_code = db.Column(db.String(255), nullable=True)
group_id = db.Column(db.Integer, db.ForeignKey('group.id'), nullable=True)
orientation = db.Column(db.String(16), default='Landscape')
status = db.Column(db.String(50), default='offline')
last_seen = db.Column(db.DateTime, nullable=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
API Endpoints
1. Player Authentication
POST /api/auth/player
Authenticate a player and receive auth code.
Request:
{
"hostname": "player-001",
"password": "your_password",
"quickconnect_code": "QUICK123" // Optional if using password
}
Response (200 OK):
{
"success": true,
"player_id": 1,
"player_name": "Demo Player",
"hostname": "player-001",
"auth_code": "abc123xyz...",
"group_id": 5,
"orientation": "Landscape",
"status": "online"
}
Error Response (401 Unauthorized):
{
"error": "Invalid credentials"
}
2. Verify Auth Code
POST /api/auth/verify
Verify an existing auth code.
Request:
{
"auth_code": "abc123xyz..."
}
Response (200 OK):
{
"valid": true,
"player_id": 1,
"player_name": "Demo Player",
"hostname": "player-001",
"group_id": 5,
"orientation": "Landscape",
"status": "online"
}
Player Configuration File
Players store their configuration in player_config.ini:
[server]
server_url = http://your-server:5000
[player]
hostname = player-001
auth_code = abc123xyz...
player_id = 1
group_id = 5
[display]
orientation = Landscape
resolution = 1920x1080
[security]
verify_ssl = true
timeout = 30
[cache]
cache_dir = ./cache
max_cache_size = 1024
[logging]
enabled = true
log_level = INFO
log_file = ./player.log
Integration with Kiwy-Signage
Step 1: Copy Authentication Module
Copy player_auth_module.py to your Kiwy-Signage project:
cp digiserver-v2/player_auth_module.py signage-player/src/player_auth.py
Step 2: Initialize Authentication
In your main signage player code:
from player_auth import PlayerAuth
# Initialize authentication
auth = PlayerAuth(config_path='player_config.ini')
# Check if already authenticated
if auth.is_authenticated():
# Verify saved credentials
valid, info = auth.verify_auth()
if valid:
print(f"Authenticated as: {info['player_name']}")
else:
# Re-authenticate
success, error = auth.authenticate(
hostname='player-001',
password='your_password'
)
else:
# First time setup
hostname = input("Enter player hostname: ")
password = input("Enter password: ")
success, error = auth.authenticate(hostname, password)
if success:
print("Authentication successful!")
else:
print(f"Authentication failed: {error}")
Step 3: Use Authentication for API Calls
# Get playlist with authentication
playlist = auth.get_playlist()
# Send heartbeat
auth.send_heartbeat(status='online')
# Make authenticated API request
import requests
auth_code = auth.get_auth_code()
player_id = auth.config.get('player', 'player_id')
server_url = auth.get_server_url()
response = requests.get(
f"{server_url}/api/playlists/{player_id}",
headers={'Authorization': f'Bearer {auth_code}'}
)
Server Setup
1. Create Players in DigiServer
Via Web Interface:
- Log in as admin (admin/admin123)
- Navigate to Players → Add Player
- Fill in:
- Name: Display name
- Hostname: Unique identifier (e.g.,
player-001) - Location: Physical location
- Password: Secure password
- Quick Connect Code: Optional easy pairing code
- Orientation: Landscape or Portrait
Via Python:
from app.extensions import db
from app.models import Player
import secrets
player = Player(
name='Office Player',
hostname='office-player-001',
location='Main Office - Reception',
auth_code=secrets.token_urlsafe(32),
orientation='Landscape'
)
player.set_password('secure_password_123')
player.set_quickconnect_code('OFFICE123')
db.session.add(player)
db.session.commit()
2. Distribute Credentials
Securely provide each player with:
- Server URL
- Hostname
- Password OR Quick Connect Code
Security Considerations
✅ Passwords: Hashed with bcrypt (cost factor 12) ✅ Auth Codes: 32-byte URL-safe tokens ✅ HTTPS: Enable SSL in production ✅ Rate Limiting: API endpoints protected (10 req/min for auth) ✅ Local Storage: Config file permissions should be 600
Troubleshooting
Player Can't Authenticate
- Check server connectivity:
curl http://your-server:5000/api/health
- Verify credentials in database
- Check server logs for authentication attempts
- Ensure hostname is unique
Auth Code Invalid
- Clear saved config:
rm player_config.ini - Re-authenticate with password
- Check if player was deleted from server
Connection Timeout
- Increase timeout in
player_config.ini:
[security]
timeout = 60
- Check network connectivity
- Verify server is running
Migration from v1
If migrating from DigiServer v1:
- Export player data from v1 database
- Create players in v2 with hostname = old username
- Set passwords using
player.set_password() - Update player apps with new authentication module
- Test authentication before full deployment
Example: Complete Player Setup
#!/usr/bin/env python3
"""
Complete player setup example
"""
from player_auth import PlayerAuth
import sys
def setup_player():
"""Interactive player setup"""
auth = PlayerAuth()
# Check if already configured
if auth.is_authenticated():
print(f"✅ Already configured as: {auth.get_hostname()}")
# Test connection
valid, info = auth.verify_auth()
if valid:
print(f"✅ Connection successful")
print(f" Player: {info['player_name']}")
print(f" Group: {info.get('group_id', 'None')}")
return True
else:
print("❌ Saved credentials invalid, reconfiguring...")
auth.clear_auth()
# First time setup
print("\n🚀 Player Setup")
print("-" * 50)
# Get server URL
server_url = input("Server URL [http://localhost:5000]: ").strip()
if server_url:
auth.config['server']['server_url'] = server_url
auth.save_config()
# Get hostname
hostname = input("Player hostname: ").strip()
if not hostname:
print("❌ Hostname required")
return False
# Authentication method
print("\nAuthentication method:")
print("1. Password")
print("2. Quick Connect Code")
choice = input("Choice [1]: ").strip() or "1"
if choice == "1":
password = input("Password: ").strip()
success, error = auth.authenticate(hostname, password=password)
else:
code = input("Quick Connect Code: ").strip()
success, error = auth.authenticate(hostname, quickconnect_code=code)
if success:
print("\n✅ Authentication successful!")
print(f" Config saved to: {auth.config_path}")
return True
else:
print(f"\n❌ Authentication failed: {error}")
return False
if __name__ == '__main__':
if setup_player():
sys.exit(0)
else:
sys.exit(1)
Files Included
player_auth_module.py- Python authentication module for playersplayer_config_template.ini- Configuration templatereinit_db.sh- Script to recreate database with new schemaPLAYER_AUTH.md- This documentation
Support
For issues or questions:
- Check server logs:
app/instance/logs/ - Check player logs:
player.log - Verify API health:
/api/health - Review authentication attempts in server logs