Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ErsatzTV/legacy/llms.txt

Use this file to discover all available pages before exploring further.

ErsatzTV Legacy ships with all endpoints open by default, making it easy to get started on a trusted home network. When you need to expose the server to less-trusted environments — or want to control which IPTV clients can access streams — ErsatzTV supports three layers of authentication: IPTV access tokens carried as query parameters, JWT bearer tokens for API and streaming protection, and full OpenID Connect (OIDC) federation for enterprise SSO. These layers can be combined: OIDC secures the web UI while JWT secures the streaming endpoints.
Do not expose ErsatzTV directly to the internet without enabling authentication. The default configuration has no access controls on any endpoint, including stream URLs, the management UI, and all API routes. At minimum, enable JWT authentication before port-forwarding or placing the server behind a reverse proxy accessible from outside your local network.

Authentication Options

No Auth (Default)

All endpoints are publicly accessible. Suitable for use on a trusted local network where you control who can reach the server.

IPTV Access Token

A JWT token appended as ?access_token= to M3U, XMLTV, and stream URLs. Allows IPTV clients to authenticate without HTTP headers.

JWT Authentication

A symmetric HMAC-SHA256 JWT secures the full API and all IPTV streaming endpoints. Tokens expire after 24 hours and must be passed as Authorization: Bearer or ?access_token=.

OpenID Connect (OIDC)

Delegates web UI authentication to an external OIDC provider (Authelia, Keycloak, Authentik, Google, etc.). The web UI requires a valid OIDC session; API calls use JWT.

IPTV Access Token

When JWT authentication is enabled, the access_token query parameter provides a way for IPTV clients — which typically cannot set custom HTTP headers — to authenticate against the M3U, XMLTV, and stream endpoints. The access token is the same JWT used for API Bearer authentication. ErsatzTV’s JWT middleware checks for this parameter on every request to the IPTV controller:
GET /iptv/channels.m3u?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
GET /iptv/xmltv.xml?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
GET /iptv/channel/2.0.ts?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
ErsatzTV propagates the token automatically within the playlist. When a request to /iptv/channels.m3u includes an access_token, the generated M3U embeds the token in all stream URLs and the XMLTV URL inside the #EXTM3U header. This means your IPTV client only needs the token in the playlist URL — every downstream URL is pre-authenticated.

Channel Logo Exception

Channel logo endpoints (/iptv/logos/) are exempt from JWT authentication, even when JWT is globally enabled. This is because logos are also displayed in the ErsatzTV management UI, which authenticates via OIDC or cookie rather than JWT. Requiring JWT on logos would break the UI’s artwork display.

JWT Authentication

JWT authentication uses a symmetric HMAC-SHA256 key configured via the application settings. When a non-empty JWT:IssuerSigningKey is present, the JWT middleware activates and all IPTV endpoints require a valid token.

Enabling JWT

Add the signing key to your ErsatzTV configuration. Using environment variables (recommended for Docker):
# Set a long, random secret — at least 32 characters
JWT__IssuerSigningKey=your-very-long-random-secret-key-here-minimum-32-chars
Or in appsettings.json:
{
  "JWT": {
    "IssuerSigningKey": "your-very-long-random-secret-key-here-minimum-32-chars"
  }
}
Use a randomly generated string of at least 32 characters for IssuerSigningKey. Short or predictable keys are vulnerable to brute-force attacks. Generate one with openssl rand -base64 48 or a similar tool.

Token Properties

Tokens generated by ErsatzTV have the following characteristics:
PropertyValue
AlgorithmHMAC-SHA256 (HS256)
Issuer validationDisabled
Audience validationDisabled
Lifetime validationEnabled — tokens expire after 24 hours
Key validationEnabled — must match JWT:IssuerSigningKey
Tokens do not carry claims (no roles, no subject). The token is valid as long as it is signed with the correct key and has not expired.

Generating a Token

ErsatzTV exposes a token generation endpoint in its API. With JWT enabled, obtain a token by calling:
curl -X POST http://ersatztv.local:8409/api/token \
  -H "Content-Type: application/json"

Using JWT for API Calls

Pass the token as a Bearer header on API requests:
curl http://ersatztv.local:8409/api/channels \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
See API Overview for the full list of available API endpoints.

Conditional IPTV Authorization

ErsatzTV uses a custom ConditionalIptvAuthorizeFilter on the IPTV controller. This filter activates JWT enforcement only when JwtHelper.IsEnabled is true — that is, only when a signing key has been configured. When the key is absent, the filter is a no-op and all IPTV endpoints remain open. This design means you do not need to change endpoint configuration when toggling auth on or off; only the key presence matters.
IPTV request received
  → JWT signing key configured?
      Yes → Require valid JWT (Bearer header or ?access_token= query param)
      No  → Allow through without authentication

OpenID Connect (OIDC)

OIDC delegates web UI login to an external identity provider. When OIDC is enabled, unauthenticated users who visit the ErsatzTV management UI are redirected to the OIDC provider’s login page. After a successful login, the provider redirects back to ErsatzTV with an authorization code, which ErsatzTV exchanges for a session cookie. OIDC secures the web UI only. It does not protect IPTV streaming or API endpoints — use JWT for those.

Enabling OIDC

Configure the four required values via environment variables or appsettings.json:
Docker Environment Variables
OIDC__Authority=https://auth.example.com
OIDC__ClientId=ersatztv
OIDC__ClientSecret=your-client-secret
# Optional: redirect users to this URL on logout
OIDC__LogoutUri=https://auth.example.com/application/o/ersatztv/end-session/
appsettings.json
{
  "OIDC": {
    "Authority": "https://auth.example.com",
    "ClientId": "ersatztv",
    "ClientSecret": "your-client-secret",
    "LogoutUri": "https://auth.example.com/application/o/ersatztv/end-session/"
  }
}
SettingRequiredDescription
OIDC:AuthorityYesThe base URL of your OIDC provider (issuer URL)
OIDC:ClientIdYesThe client ID registered with your OIDC provider
OIDC:ClientSecretYesThe client secret for the confidential client
OIDC:LogoutUriNoIf set, users are redirected here when they sign out of ErsatzTV

OIDC Flow Details

ErsatzTV uses the Authorization Code flow with PKCE. The callback URL that must be registered in your OIDC provider is:
https://ersatztv.example.com/callback
Only the openid scope is requested. ErsatzTV uses the session solely for authentication (proving identity) — it does not request profile or email scopes. Tokens are stored in a secure, HTTP-only, SameSite=None cookie, which requires HTTPS for the OIDC flow to function correctly.

Provider Examples

  1. In Authentik, create a new OAuth2/OpenID Provider.
  2. Set Client Type to Confidential.
  3. Add https://ersatztv.example.com/callback as a Redirect URI.
  4. Copy the Client ID and Client Secret to ErsatzTV’s OIDC settings.
  5. Set OIDC:Authority to your Authentik base URL, e.g. https://auth.example.com.

Combining JWT and OIDC

JWT and OIDC can be enabled simultaneously. In this configuration:
  • The web UI is protected by OIDC — users must log in through the identity provider.
  • IPTV endpoints and the REST API are protected by JWT — clients pass Authorization: Bearer or ?access_token=.
This is the recommended setup for production deployments exposed to the internet. The web UI for administration is locked down via SSO, while IPTV clients use a long-lived JWT token embedded in their playlist URL.
Web browser → OIDC login → session cookie → management UI ✓
IPTV client → ?access_token=<jwt> → stream endpoint ✓
API call    → Authorization: Bearer <jwt> → API endpoint ✓
When OIDC is enabled, Razor pages (the web UI) require an authenticated OIDC session. When JWT is enabled, API controllers and IPTV endpoints require a valid JWT. The two schemes operate independently and do not interfere with each other.

Build docs developers (and LLMs) love