Auch verfügbar in: DE Deutsch

Auth & Users

Inhalt

Authentication and authorization are handled by Better Auth (apps/api/src/auth.ts). Sessions are managed server-side; all role checks are enforced at the API layer.


Authentication Providers

Provider Status Notes
Email / password Available Default — enabled on all instances
OIDC (Authentik, Keycloak, etc.) Planned v1.0 OIDC_ISSUER, OIDC_CLIENT_ID and OIDC_CLIENT_SECRET appear in .env.example but are not read by the code yet
Passkey / WebAuthn Planned v1.0 Passwordless, device-bound credentials
Social OAuth (GitHub, Google, etc.) Not planned Out of scope for self-hosted use case

User Roles

Role Description Permissions
Admin Full instance control Everything — settings, users, content, theme, legal
Moderator Content moderation Role exists in the schema but currently has no rights of its own in the code. Reports and takedowns are admin-only
Creator Content creation Upload videos, manage own channels and videos, edit Studio
Viewer Consumption Watch public, unlisted and logged_in videos, comment where enabled. The code currently has no role check on upload

Role assignment is managed in /admin/users. A user can hold one role at a time. Admins can promote or demote any account. New accounts get the Creator role by default.


Admin Bootstrap

On a fresh instance, the first-run wizard at /setup normally creates the admin account and sets the Admin role directly. The INITIAL_ADMIN_EMAIL environment variable is an optional fallback and also pre-fills and locks the wizard's email field.

How it works:

  1. Set INITIAL_ADMIN_EMAIL=you@example.com in your environment or compose file
  2. Register a new account using that exact email address
  3. The Better Auth hook databaseHooks.user.create.after checks the email and automatically promotes the account to Admin

The hook runs on every sign-up, and this address may register even when registration is closed. Since email addresses are unique, leaving the variable set is harmless once the account exists. Further promotions are done through the admin panel.


Session Management

  • Cookie: HTTP-only session cookie, set on successful login
  • SameSite: Lax — protects against CSRF while allowing top-level navigation
  • Secure flag: Better Auth default, not configured separately in apps/api/src/auth.ts
  • Session lifetime: Better Auth default, not configured separately in apps/api/src/auth.ts
  • Storage: Sessions are stored server-side in the Postgres database (via Better Auth's built-in session table)

Clients never receive the raw session secret. All session validation happens on the API.


Visibility Enforcement

Video visibility is enforced centrally via canViewVideo() at every read endpoint. No client-side gating — the check happens in the tRPC procedure before any data is returned.

Visibility level Who can watch
public Everyone, including unauthenticated visitors
unlisted Anyone with the direct link — not shown in feeds or search
logged_in Authenticated users only (any role)
private Video owner and Admins only

There are no signed playback URLs. HLS files are served directly by the container via /s3/. The visibility check covers the video data returned by the API.


Rate Limiting

Rate limits are enforced at the Fastify layer before requests reach tRPC.

Endpoint group Limit
Global none, only individual routes are limited
Auth routes /api/auth/* (login, sign-up, reset) 20 requests / minute / IP
Video upload /api/upload 10 requests / minute / IP
Setup logo /api/setup/logo 6 requests / minute / IP

Routes without their own values use RATE_LIMIT_MAX (default 120) and RATE_LIMIT_WINDOW_MS (default 60000). Counters are kept in Redis via @fastify/rate-limit (key prefix play-rl:). In the all-in-one container, Redis is internal and always available.


Registration Control

/admin/settings and the first-run wizard offer three modes (Open, Invite only, Closed). The setting lives in the database (SiteSettings.registrationMode). When registration is not open:

  • Sign-ups are rejected with 403, error code REGISTRATION_CLOSED or INVITE_REQUIRED
  • Existing accounts are unaffected
  • The address from INITIAL_ADMIN_EMAIL can still register

Invite tokens are not implemented yet, so "Invite only" currently blocks all new sign-ups. There is no way to create accounts from /admin/users.