Every server is its own trust anchor
A media server owns a key pair, issues tokens and decides about permissions on its own. The relay verifies tokens only against the server's public key; accounts, permissions and user data live exclusively on the media server.
Server identity
On first start the server generates an Ed25519 key pair. The server ID is the fingerprint of the public key; clients pin it at pairing.
Ed25519
Initial setup without a web UI
The server writes a one-time setup code to console and log and announces itself via mDNS on the LAN. The user enters the code in the client, creates the admin account and pins the server key. Headless: tenjin-server --setup.
mDNS · setup code
Relay identity
The relay is reachable under a domain name and carries a public certificate, for example from Let's Encrypt. Servers register with a registration code and keep an outbound control connection; no port forwarding is needed.
Let's Encrypt · registration code
Login and tokens
Password verification always happens end-to-end between client and media server, even in relay mode C; the login request is passed through there. A PAKE scheme (OPAQUE) is planned so the password never reaches the server in plain text.
The server issues a short-lived access token (about 15 minutes) and a device-bound refresh token. The refresh token is replaced on every renewal. If a replaced token reappears after a grace period, the server revokes all tokens of the device and warns in the activity log. Detection, grace period and validity (default 30 days) are configured by the administrator. The relay issues no tokens of its own.
| Claim | Content |
|---|---|
srv |
Server ID of the issuer |
sub |
Local user ID |
libs |
Granted library IDs |
age |
Age rating limit |
bw |
Maximum bitrate locally and remotely |
streams |
Maximum concurrent streams |
dev |
Device ID |
exp |
Expiry time |
Tokens are signed with the server key; the relay verifies them offline. Quick Connect signs in TVs and other devices without a keyboard: the device fetches a six-digit code, a signed-in phone or computer approves it, and the device receives its own token pair.
Three paths, three levels of trust
Path B (default): the relay sees
- Server ID and device ID of the connection
- Timestamps, packet sizes, data volume
- The token signature, which it verifies offline
Path B: the relay does not see
- Passwords or credentials
- Titles, images, streams, progress
- Session keys of the QUIC connection
Path C (relay termination) has to be enabled explicitly by the relay administrator per server, and the server administrator can refuse it for their server. Only then does the relay see contents, for example to cache or transcode streams.
Account linking and sync
Anyone with accounts on two servers can link them: server 1 generates a random 128-bit sync ID and a link secret, the client hands both to server 2, and both servers exchange a key for this pairing. Favourites and progress then travel end-to-end between the servers via the relay; the relay sees only the pseudonymous sync ID.
Further measures
- Brute-force protection: delay and lockout after failed attempts; audit log for logins and admin actions.
- Secrets (API keys, SMB, NFS and WebDAV credentials) are stored encrypted, with the key in the operating system's key store: DPAPI (Windows), Keychain (macOS), key file with permissions 0600 (Linux, QTS).
- Image addresses carry no tokens and are cached only when versioned; a changed image has a new address.
- The player fetches streams through a local proxy of the client; tokens stay in the client.
- The relay control channel is outbound; no port has to be opened on the media server.
Status and limits
Tenjin 0.1.0 is a development build: the database schema and the protocol may still change before 1.0. An external security review is still outstanding; the measures above describe the concept and the current state of implementation. Anyone who does not trust the relay operator runs the relay themselves or stays with path A.
