Vai al contenuto principale

Autenticazione

An authentication gate plugin makes viewers sign in before reaching the resources selected by the server operator. The plugin supplies the login method, such as OAuth, a magic link, SAML, or a shared password. Owncast enforces the selected access mode.

  • Il tuo plugin è il fornitore di identità. Rende visibile la schermata di login, comunica con il fornitore esterno e decide chi è autorizzato ad accedere.
  • The Owncast host is the gatekeeper and session authority. It owns the session cookie, enforces the selected access mode, and never puts your plugin in the per-request hot path.
Owncat informs youRichiede auth.gate

Tutto su questa pagina necessita del permesso auth.gate, oltre a users.register per creare l'utente autenticato e http.serve per visualizzare il flusso di login.

Cosa viene limitato

When an auth.gate plugin is enabled, the viewer page, chat, embeds, /api/config, and the rest of the public web surface require login. A short list of routes stays public in every mode, including Owncast's admin pages (they keep their own admin authentication, so an operator can always disable a broken gate), the instance logo, and the ActivityPub federation endpoints. See what bypasses the gate for the full list.

The operator selects one cumulative access mode on the plugin's Authentication tab:

Access modeEffect
Website only (default)The web interface requires sign-in. /hls/*, /api/status, and Owncast Directory listing stay public.
Website, video players, and other resourcesAlso gates Owncast-hosted /hls/*. Players such as VLC cannot complete the browser login. /api/status and directory listing stay public.
Website, video players, and server status requestsGates the web interface, Owncast-hosted /hls/*, and /api/status. Owncast Directory listing is disabled.

The modes are cumulative. There is no status-only mode that hides /api/status while leaving HLS public. The default protects the website without breaking existing players or uptime monitors.

Selecting either stream-protection mode blocks native players. VLC, QuickTime, mobile apps, and restreamers cannot complete a browser login or carry the session cookie. An Authorization header or query token does not bypass the gate.

A viewer with a valid session is always let through, regardless of the selected mode.

Owncat warns youDistribuire il tuo video con avvertenza di archiviazione esterna (Archiviazione oggetti/CDN)

When distributing your video stream directly from your server, stream protection is airtight: every byte flows through Owncast. Con Archiviazione Oggetti o CDN, le playlist vengono riscritte in URL remoti assoluti e i segmenti vengono recuperati direttamente dal bucket, quindi il gate non vede mai quelle richieste. Il gating ferma comunque un visitatore anonimo dall'scoprire l'elenco dei segmenti, ma un URL di segmento trapelato o condiviso rimane accessibile. Stream protection + local distribution is airtight. Stream protection + Object Storage is good friction, not airtight.

Come funziona

Once the gate is armed, every non-exempt request is checked. Under stream protection that includes each HLS segment, which a live viewer pulls every few seconds. Chiamare il motore incorporato del tuo plugin in ciascuna di quelle richeste manderebbe in tilt il server, quindi il plugin viene mantenuto lontano dal percorso critico:

QuandoCostoCosa succede
Every non-exempt requestVerifica la firma e la scadenza del cookievalid passes. Missing or invalid gets a redirect to login, or a 401 for anything that is not a GET or HEAD
La pagina / si carica soloChiamata al motore opzionale: onAuthCheckri-verifica contro il tuo fornitore, restituisce ok / refresh / deny

Il tuo plugin esegue solo il flusso di login (rara, circa una volta per sessione di visualizzazione) e l'opzionale onAuthCheck per ogni caricamento di pagina. L'host di Owncast crea e verifica un cookie di sessione firmato in modo che il check per ogni richiesta sia solo firma e scadenza: nessuna ricerca nel database, nessuna chiamata al plugin.

The cookie is a signed envelope carrying an Owncast access token plus a session expiry. The host mints a fresh access token for the user each time it grants a session. The Owncast host owns the cookie end to end: it reserves the cookie name (owncast_session), signs it with a host-held secret, and attaches it to the response. Il tuo plugin non vede né imposta il token, quindi non può falsificare né trapelare uno. (Questo è anche il modo in cui la chat rileva automaticamente l'identità del visualizzatore. Vedi Identità chat qui sotto.)

Creare un plugin di gate

Un plugin di gate è un plugin che eroga HTTP con un flusso di login. Il ciclo di controllo, per convenzione, è radicato nello spazio dei nomi del tuo plugin /plugins/\<your-slug>/:

Tre pezzi fanno il lavoro:

  1. Registra l'utente. Trasforma l'identità esterna in un vero utente di Owncast con owncast.users.register. Passa un authId stabile e specifico del fornitore (es. "github:583231"). L'host lo spazia in base al tuo slug in modo che i plugin non possano sovrapporsi o imitarsi a vicenda.
  2. Concedi la sessione. Chiama owncast.auth.grantSession con quel userId. L'host di Owncast crea il cookie firmato e lo allega alla risposta in volo. Questo funziona solo all'interno di un gestore onHttpRequest.
  3. Reindirizza a casa. L'host di Owncast aggiunge un parametro di query return_to quando rimbalza un visitatore non autenticato alla tua schermata di login e sanitizza a un percorso di stessa origine (quindi non può essere trasformato in un reindirizzamento aperto). Invia lì il visualizzatore dopo un login riuscito.

Per disconnettere un visualizzatore, chiama owncast.auth.endSession() e reindirizza. Il tuo plugin controlla comunque dove andare (potrebbe rimanere sul logout del fornitore stesso).

Revoca con onAuthCheck

Le sessioni sono senza stato, quindi non c'è un elenco per ogni richiesta "questo utente è ancora autorizzato". Ciò metterebbe di nuovo il plugin nel percorso critico. Invece, definisci il gestore opzionale onAuthCheck. Si attiva con ogni caricamento di pagina / con l'identità del visualizzatore risolta, e restituisce ok, refresh (riemetti il cookie, opzionalmente con un nuovo TTL per una scadenza scorrevole) o deny (termina la sessione e rimbalza al login). Un plugin supportato da un fornitore ri-verifica l'appartenenza qui (l'org è ancora valida? l'account non è stato eliminato?).

Poiché il controllo viene eseguito solo su /, un visualizzatore che revoci mantiene attivo qualsiasi scheda aperta finché non si aggiorna o il cookie scade. La sessione TTL è il duro divieto per la revoca, quindi mantienila breve se una rapida revoca è importante.

Esempio pratico: un gate con password condivisa

Il plugin di esempio basic-auth è il gate più semplice possibile: una password condivisa, un'identità "Guest" condivisa, nessun fornitore esterno. È disponibile sia in examples/js/basic-auth sia in examples/python/basic-auth.

Il suo manifesto dichiara i permessi e un singolo campo di configurazione per la password:

{
"name": "Basic Auth",
"slug": "basic-auth",
"version": "0.1.0",
"permissions": ["auth.gate", "users.register", "http.serve", "storage.kv"],
"config": {
"password": {
"type": "string",
"default": "letmein",
"description": "Shared password viewers must enter to watch"
}
}
}

Il gestore mostra un modulo di password a /, verifica la password inviata rispetto al valore configurato e, in caso di successo, registra l'identità condivisa, concede una sessione e reindirizza di nuovo. onAuthCheck legge un flag revoked che può essere attivato dall'amministratore per allontanare tutti al successivo caricamento di pagina. (L'helper page() che genera il modulo HTML è omesso qui per brevità. Vedi il codice sorgente di esempio.)

const { definePlugin, owncast, authCheck } = require('@owncast/plugin-sdk');

module.exports = definePlugin({
onHttpRequest(req) {
const query = req.query || {};
const returnTo = query.return_to || '/';

if (req.method === 'GET' && req.path === '/') {
return {
status: 200,
headers: { 'content-type': 'text/html' },
body: page(returnTo),
};
}

if (req.path === '/login') {
const expected = owncast.config.get('password', 'letmein');
if ((query.password || '') !== expected) {
return {
status: 200,
headers: { 'content-type': 'text/html' },
body: page(returnTo, 'Incorrect password.'),
};
}
// Everyone who knows the password shares one authenticated identity.
const { userId } = owncast.users.register({
authId: 'shared',
displayName: 'Guest',
});
owncast.auth.grantSession({ userId });
return { status: 302, headers: { Location: returnTo } };
}

if (req.path === '/logout') {
owncast.auth.endSession();
return { status: 302, headers: { Location: '/' } };
}

// Admin-only revocation toggle. req.authenticated is true for admins only.
if (req.path === '/revoke' || req.path === '/unrevoke') {
if (!req.authenticated) return { status: 403, body: 'admin only' };
owncast.kv.set('revoked', req.path === '/revoke' ? '1' : '');
return {
status: 200,
body: req.path === '/revoke' ? 'revoked' : 'unrevoked',
};
}

return { status: 404, body: 'not found' };
},

// Re-validate on each page load. While revoked, end every session.
onAuthCheck() {
if (owncast.kv.get('revoked') === '1') return authCheck.deny('access has been revoked');
return authCheck.ok();
},
});

Per un reale flusso OAuth (CSRF state in storage.kv, uno scambio di codice su network.fetch, enforcement dell'appartenenza all'org e un URL di callback costruito da owncast.server.info()), vedere l'esempio github-auth nel SDK.

Abilitare il gate

Dichiarare auth.gate non fa nulla da solo. Il gate è attivato da abilitare il plugin attraverso il normale ciclo di attivazione/disattivazione nell'amministrazione. Disabilitalo e il gate viene eliminato istantaneamente.

  • Solo un plugin auth.gate può essere abilitato alla volta. Owncast rifiuta di attivare un secondo mentre uno è già attivo ("disabilita prima l'altro").
  • Configura prima di abilitare. Un plugin può essere installato e configurato mentre è disabilitato, quindi abilitato per andare in diretta. Utilizza il modulo di configurazione generato automaticamente per credenziali come un OAuth client ID e secret.

Fallisci in chiusura

La postura del gate è disaccoppiata dalla salute del tuo plugin. Se il gate è attivato ma il plugin è non disponibile (crash, caricamento fallito, errore o disabilitato automaticamente dopo ripetuti fallimenti), Owncast nega tutto il traffico degli spettatori e serve una pagina statica "autenticazione temporaneamente non disponibile". Non si apre mai. L'amministratore è sempre raggiungibile (i percorsi dell'amministratore utilizzano l'autenticazione di base esistente di Owncast e bypassano il gate), quindi puoi correggere la configurazione o disabilitare il plugin. Le sessioni già valide sopravvivono a un'interruzione, poiché il controllo di un cookie non richiede alcuna chiamata al plugin.

A gate that is enabled but not running is still a gate. No access-policy setting can turn a failing-closed gate into an open one.

Cosa bypassa il gate

The gate covers the otherwise-public surface. Routes that enforce their own credentials bypass it. The selected access mode also leaves some resources public.

Always exempt:

  • The active gate plugin's own namespace /plugins/\<your-slug>/* and its static assets, so the login screen remains reachable.
  • /admin/* and /api/admin/*, which use admin authentication.
  • External API routes under /api/integrations/, which validate their own Bearer tokens.
  • Static viewer assets needed to render the page. HTML entry points are still gated.
  • /api/yp, which the Owncast Directory fetches anonymously. The most restrictive mode disables directory listing and makes this endpoint return 404.
  • /logo and /logo/external, the instance logo, which the viewer shell and federation metadata both reference.
  • /federation/*, the ActivityPub protocol surface. Those handlers enforce Owncast's own federation and privacy settings.

Mode-dependent:

  • /hls/* stays public only in Website only mode.
  • /api/status stays public in Website only and Website, video players, and other resources modes.

Everything else is gated, including embeds and /api/config.

Dettagli della sessione

  • Stateless signed cookie named owncast_session, HttpOnly, Secure (on HTTPS requests), SameSite=Lax, Path=/. Lax piuttosto che Strict perché il callback del fornitore è un reindirizzamento a livello di dominio tra siti. The host owns the name: a plugin that tries to set it in its own response has that header stripped.
  • TTL is set by your plugin when it calls grantSession({ ttl }), defaulting to 24 hours and capped at 30 days. A sliding refresh is available through onAuthCheck's refresh verdict. Poiché il TTL è il divieto di revoca, è un reale comando di sicurezza.
  • Il segreto di firma è responsabilità dell'host di Owncast. Viene generato automaticamente al primo utilizzo e mantenuto nella configurazione. Ruotarlo invalida ogni sessione (un pulsante di emergenza). Gli autori del plugin non lo toccano mai, ed è separato da qualsiasi segreto di client OAuth, che riguarda la configurazione del tuo plugin.

Identità chat

Un login del gate produce automaticamente un'identità chat autenticata. Because users.register creates or links a real Owncast user (marked authenticated, with the display name you passed, or a generated one if you passed none) and the session cookie carries an access token for that user, chat reads the identity straight from the cookie: when /ws (or a chat REST call) arrives with no ?accessToken= query parameter, it falls back to the access token in the gate cookie. Nessun token viene mai trasportato nel localStorage del browser. The viewer signs in once and shows up in chat under that name.

Correlati

  • Permessi: auth.gate, users.register
  • APIs di Owncast: users.register, auth.grantSession, auth.endSession
  • Eventi: il gestore onAuthCheck
  • Fornitura HTTP: il modello di richiesta su cui è costruito il flusso di login

Improve this page

See something missing or incorrect? Edit this page and improve the documentation for everyone.

Contributors to this documentation