Security and Secrets
Three Important Secrets
Section titled “Three Important Secrets”SyncTV has three high-impact secrets. They have different purposes and should not be reused.
| Setting | Purpose | Must remain stable | Impact if lost or leaked |
|---|---|---|---|
jwt.secret | Signs access, refresh, and guest tokens | Can be rotated, but affects sessions | A leaked value may allow forged tokens |
security.opaque_server_setup_secret | Server setup secret for OPAQUE password auth | Yes | Changing it can make OPAQUE password records unverifiable |
security.credential_encryption_key | Encrypts provider credentials | Yes | Losing it can make encrypted provider credentials unreadable |
Use environment variables or secret files in production. Do not commit these values.
jwt.secret
Section titled “jwt.secret”Purpose: signs login tokens.
Requirements:
- At least 32 characters.
- High entropy.
- Not a placeholder, project name, domain, date, or common word.
Generate:
openssl rand -base64 32Recommended YAML:
jwt: secret_file: "/run/secrets/jwt_secret"Environment variables:
SYNCTV_JWT_SECRET=...SYNCTV_JWT_SECRET_FILE=/run/secrets/jwt_secretRotating it can invalidate existing access and refresh tokens. Rotate immediately if it may have leaked.
Token Durations
Section titled “Token Durations”| Field | Default | Purpose |
|---|---|---|
jwt.access_token_duration_hours | 1 | Access token lifetime |
jwt.refresh_token_duration_days | 30 | Refresh token lifetime |
jwt.guest_token_duration_hours | 4 | Guest token lifetime |
jwt.clock_skew_leeway_secs | 60 | Clock skew tolerance |
For internet-facing deployments, keep access tokens short and rely on refresh rotation. Use NTP instead of increasing clock skew to hide server time drift.
security.credential_encryption_key
Section titled “security.credential_encryption_key”Purpose: encrypts sensitive provider credentials such as tokens, API keys, and provider secrets.
Format:
- 64 hexadecimal characters.
- Equivalent to a 32-byte AES-256-GCM key.
Generate:
openssl rand -hex 32Recommended YAML:
security: credential_encryption_key_file: "/run/secrets/credential_encryption_key"Environment variables:
SYNCTV_SECURITY_CREDENTIAL_ENCRYPTION_KEY=...SYNCTV_SECURITY_CREDENTIAL_ENCRYPTION_KEY_FILE=/run/secrets/credential_encryption_keyBack it up securely before storing encrypted provider credentials. Do not rotate it casually without a migration plan.
security.opaque_server_setup_secret
Section titled “security.opaque_server_setup_secret”Purpose: stable server secret used by OPAQUE password authentication.
Generate:
openssl rand -base64 48Recommended YAML:
security: opaque_server_setup_secret_file: "/run/secrets/opaque_server_setup_secret"Environment variables:
SYNCTV_SECURITY_OPAQUE_SERVER_SETUP_SECRET=...SYNCTV_SECURITY_OPAQUE_SERVER_SETUP_SECRET_FILE=/run/secrets/opaque_server_setup_secretImportant constraints:
- Do not reuse
jwt.secret. - Do not generate a new value on every container start.
- Keep the value stable across Helm upgrades and redeployments.
- Changing it incorrectly can break existing password login records.
Password Complexity
Section titled “Password Complexity”Default:
password_complexity: min_length: 8 require_uppercase: true require_lowercase: true require_digit: true require_special: false max_repeated_chars: 3This applies to user account passwords, not room passwords.
Production policy usually benefits more from longer passwords and rate limits than from forcing many special characters on clients with poor text input.
max_repeated_chars=0 disables the repeated-character check.
CORS and Trusted Proxies
Section titled “CORS and Trusted Proxies”CORS controls which browser origins may call the API.
server: cors_allowed_origins: - "https://app.example.com"Origins must not include paths, query strings, or fragments.
Trusted proxies control whether SyncTV trusts forwarding headers such as X-Forwarded-For.
server: trusted_proxies: - "10.0.0.0/8"Only add proxy IPs or CIDRs that you control. If this list is empty, SyncTV uses the socket peer address and does not trust forwarded client IP headers.
WebAuthn and 2FA
Section titled “WebAuthn and 2FA”WebAuthn/passkey configuration is documented in WebAuthn and Passkeys.
User-level two-factor authentication is a preference, not a global YAML switch. Before enabling 2FA, a user must have at least two usable local verification methods:
- Password.
- WebAuthn/passkey.
- Verified email.
OAuth2 does not participate in local 2FA, but a user with 2FA enabled may still log in through OAuth2. OAuth2 sessions are treated as an accepted authentication context for token refresh.
When 2FA is enabled, local one-factor tokens should not be accepted as enough for refresh or security-sensitive preference changes.