From 59f5ec798ed1e0318addb66fe8753364ef2e6643 Mon Sep 17 00:00:00 2001 From: Priveetee Date: Wed, 5 Aug 2026 11:09:35 +0200 Subject: [PATCH 1/8] docs: document account session configuration --- docs/.vitepress/config.mts | 10 ++++++ docs/es/self-hosting/authentication.md | 46 ++++++++++++++++++++++++++ docs/fr/self-hosting/authentication.md | 46 ++++++++++++++++++++++++++ docs/self-hosting/authentication.md | 30 +++++++++++++++-- docs/self-hosting/configuration.md | 21 ++++++++++++ docs/self-hosting/troubleshooting.md | 20 +++++++---- 6 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 docs/es/self-hosting/authentication.md create mode 100644 docs/fr/self-hosting/authentication.md diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 753a97b..d84d2f5 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -23,6 +23,7 @@ export default defineConfig({ nav: [ { text: "Accueil", link: "/fr/" }, { text: "Prérequis", link: "/fr/self-hosting/prerequisites" }, + { text: "Sessions", link: "/fr/self-hosting/authentication" }, { text: "Guide en anglais", link: "/" }, { text: "Code source", link: "https://github.com/TypeType-Video/TypeType" }, ], @@ -35,6 +36,10 @@ export default defineConfig({ text: "Prérequis et ressources", link: "/fr/self-hosting/prerequisites", }, + { + text: "Sessions de compte", + link: "/fr/self-hosting/authentication", + }, ], }, ], @@ -81,6 +86,7 @@ export default defineConfig({ nav: [ { text: "Inicio", link: "/es/" }, { text: "Requisitos", link: "/es/self-hosting/prerequisites" }, + { text: "Sesiones", link: "/es/self-hosting/authentication" }, { text: "Guía en inglés", link: "/" }, { text: "Código fuente", link: "https://github.com/TypeType-Video/TypeType" }, ], @@ -93,6 +99,10 @@ export default defineConfig({ text: "Requisitos y recursos", link: "/es/self-hosting/prerequisites", }, + { + text: "Sesiones de cuenta", + link: "/es/self-hosting/authentication", + }, ], }, ], diff --git a/docs/es/self-hosting/authentication.md b/docs/es/self-hosting/authentication.md new file mode 100644 index 0000000..3e282a5 --- /dev/null +++ b/docs/es/self-hosting/authentication.md @@ -0,0 +1,46 @@ +# Sesiones de cuenta + +Después de iniciar sesión de forma local o mediante OIDC, el token de acceso de +TypeType dura una hora. Una sesión de actualización renueva automáticamente ese +token sin pedir otro inicio de sesión. + +## Duración de la sesión + +La sesión de actualización dura 30 días de forma predeterminada. Puedes elegir una +duración de 1 a 365 días en `.env`: + +```dotenv +AUTH_SESSION_TTL_DAYS=90 +``` + +La nueva duración se aplica a las sesiones creadas o renovadas después del cambio. +Vuelve a crear Server para aplicar la configuración: + +```sh +docker compose up -d --force-recreate typetype-server +``` + +## HTTPS y redes locales + +De forma predeterminada, la cookie de actualización es `HttpOnly`, `Secure` y +`SameSite=None`. Usa HTTPS para cualquier instancia pública. + +En una red local de confianza que no pueda usar HTTPS, una opción de compatibilidad +permite que la cookie funcione mediante HTTP con `SameSite=Lax`: + +```dotenv +AUTH_ALLOW_INSECURE_COOKIES=true +``` + +::: danger +No actives esta opción en Internet ni en una red que no sea de confianza. La cookie +podría viajar por una conexión HTTP sin cifrar. +::: + +Un cierre de sesión exactamente después de una hora suele indicar que la cookie de +actualización no fue enviada o aceptada. Comprueba también que `ALLOWED_ORIGINS` +contenga exactamente el origen del navegador. + +La guía completa en inglés explica la +[autenticación](/self-hosting/authentication) y la +[resolución de cierres de sesión](/self-hosting/troubleshooting#unexpected-sign-outs). diff --git a/docs/fr/self-hosting/authentication.md b/docs/fr/self-hosting/authentication.md new file mode 100644 index 0000000..5f93dc1 --- /dev/null +++ b/docs/fr/self-hosting/authentication.md @@ -0,0 +1,46 @@ +# Sessions de compte + +Après une connexion locale ou OIDC, le jeton d'accès TypeType est valable pendant +une heure. Une session de rafraîchissement renouvelle automatiquement ce jeton, sans +demander une nouvelle connexion. + +## Durée de la session + +La session de rafraîchissement dure 30 jours par défaut. Vous pouvez choisir une +durée de 1 à 365 jours dans `.env` : + +```dotenv +AUTH_SESSION_TTL_DAYS=90 +``` + +La nouvelle durée s'applique aux sessions créées ou renouvelées après le changement. +Recréez Server pour appliquer la configuration : + +```sh +docker compose up -d --force-recreate typetype-server +``` + +## HTTPS et réseaux locaux + +Par défaut, le cookie de rafraîchissement est `HttpOnly`, `Secure` et +`SameSite=None`. Utilisez HTTPS pour toute instance publique. + +Sur un réseau local de confiance qui ne peut pas utiliser HTTPS, une option de +compatibilité permet au cookie de fonctionner en HTTP avec `SameSite=Lax` : + +```dotenv +AUTH_ALLOW_INSECURE_COOKIES=true +``` + +::: danger +N'activez pas cette option sur Internet ou sur un réseau non fiable. Le cookie peut +alors circuler dans une connexion HTTP non chiffrée. +::: + +Une déconnexion exactement après une heure indique généralement que le cookie de +rafraîchissement n'a pas été envoyé ou accepté. Vérifiez aussi que +`ALLOWED_ORIGINS` contient exactement l'origine du navigateur. + +Le guide complet en anglais détaille +[l'authentification](/self-hosting/authentication) et le +[dépannage des déconnexions](/self-hosting/troubleshooting#unexpected-sign-outs). diff --git a/docs/self-hosting/authentication.md b/docs/self-hosting/authentication.md index 0419036..adbd49b 100644 --- a/docs/self-hosting/authentication.md +++ b/docs/self-hosting/authentication.md @@ -95,8 +95,16 @@ reference and the current provider documentation for its exact schema. ## Session lifetime After local or OIDC login, the access token lasts one hour. The browser also receives -a rotating refresh cookie valid for 30 days, so normal access-token expiry should be -silent. There is no separate “remember me” duration setting. +a rotating refresh cookie, so normal access-token expiry should be silent. The refresh +session lasts 30 days by default. Set `AUTH_SESSION_TTL_DAYS` in `.env` to choose a +value from 1 to 365 days: + +```dotenv +AUTH_SESSION_TTL_DAYS=90 +``` + +This duration applies to newly issued and renewed sessions. Existing database rows +keep their current expiry until the next successful refresh or login. The refresh cookie is `HttpOnly`, `Secure`, and `SameSite=None`. A public deployment therefore needs HTTPS, the correct `ALLOWED_ORIGINS`, and proxy handling that keeps @@ -104,6 +112,24 @@ credentialed requests intact. See [Unexpected sign-outs](./troubleshooting#unexpected-sign-outs) if a user is logged out while active. +For a trusted local network that cannot use HTTPS, an explicit compatibility option +can issue the refresh cookie without `Secure` and with `SameSite=Lax`: + +```dotenv +AUTH_ALLOW_INSECURE_COOKIES=true +``` + +::: danger +Do not enable this option on a public or untrusted network. Account refresh cookies +can travel over unencrypted HTTP. HTTPS remains the supported default. +::: + +After changing either variable, recreate Server: + +```sh +docker compose up -d --force-recreate typetype-server +``` + This explanation follows the behavior questioned by [Toni-Vide in discussion #162](https://github.com/TypeType-Video/TypeType/discussions/162) and verified in the current authentication source. diff --git a/docs/self-hosting/configuration.md b/docs/self-hosting/configuration.md index 7a0efdf..f714e98 100644 --- a/docs/self-hosting/configuration.md +++ b/docs/self-hosting/configuration.md @@ -50,6 +50,27 @@ docker compose up -d --force-recreate typetype-server This diagnostic was confirmed through [hulmgulm's first-admin report](https://github.com/TypeType-Video/TypeType/discussions/151). +## Account sessions + +| Variable | Default | Purpose | +| --- | --- | --- | +| `AUTH_SESSION_TTL_DAYS` | `30` | Refresh-session lifetime in days, clamped to `1`–`365` | +| `AUTH_ALLOW_INSECURE_COOKIES` | `false` | Allows refresh cookies over plain HTTP with `SameSite=Lax` | + +Access tokens always last one hour. A valid refresh session renews them silently, so +`AUTH_SESSION_TTL_DAYS` controls how long an account can remain signed in without a +new login. + +Keep `AUTH_ALLOW_INSECURE_COOKIES=false` for HTTPS and every public deployment. Set +it to `true` only when a trusted local-only instance must run over plain HTTP. This +weakens transport security; see [Session lifetime](./authentication#session-lifetime). + +Recreate Server after changing either value: + +```sh +docker compose up -d --force-recreate typetype-server +``` + ## Database and cache The bundled PostgreSQL service uses these values: diff --git a/docs/self-hosting/troubleshooting.md b/docs/self-hosting/troubleshooting.md index bfd5bec..1a72755 100644 --- a/docs/self-hosting/troubleshooting.md +++ b/docs/self-hosting/troubleshooting.md @@ -92,13 +92,13 @@ original [community diagnosis](https://github.com/TypeType-Video/TypeType/discus ## Unexpected sign-outs {#unexpected-sign-outs} -An account access token lasts one hour, but the refresh session lasts 30 days. The -Frontend refreshes automatically when an authenticated request returns `401`, so a -sign-out at the one-hour mark is not expected normal behavior. +An account access token lasts one hour, but the refresh session lasts 30 days by +default. The Frontend refreshes automatically when an authenticated request returns +`401`, so a sign-out at the one-hour mark is not expected normal behavior. Check: -1. The page uses HTTPS on a public domain. The refresh cookie is `Secure`. +1. The page uses HTTPS. The refresh cookie is `Secure` by default. 2. `ALLOWED_ORIGINS` contains the exact browser origin. 3. Login and `/api/auth/refresh` requests include credentials and are not stripped by a custom proxy. @@ -110,9 +110,15 @@ sets `JWT_SECRET`. That invalidates the old one-hour access token, but the norma refresh flow should recover immediately when the PostgreSQL session and refresh cookie are still present. A restart alone should therefore not require a new login. -There is no admin setting that extends the 30-day lifetime. If the problem continues, -capture Server logs around `/auth/refresh`, the browser response status, and the -deployed revisions. Do not include the cookie or any bearer token. +For a trusted local-only instance that cannot use HTTPS, set +`AUTH_ALLOW_INSECURE_COOKIES=true` and recreate `typetype-server`. This deliberately +weakens cookie transport security and must not be used on a public or untrusted +network. `AUTH_SESSION_TTL_DAYS` can change the refresh lifetime from 1 to 365 days. +See [Session lifetime](./authentication#session-lifetime). + +If the problem continues, capture Server logs around `/auth/refresh`, the browser +response status, and the deployed revisions. Do not include the cookie or any bearer +token. This checklist follows the unexpected behavior reported by [Toni-Vide in discussion #162](https://github.com/TypeType-Video/TypeType/discussions/162). From 57bc7901925e32718bb769c7a566bc33202b5cdb Mon Sep 17 00:00:00 2001 From: arcoast <81871508+arcoast@users.noreply.github.com> Date: Mon, 10 Aug 2026 20:46:05 +0100 Subject: [PATCH 2/8] docs: add Android OIDC callback URL Thx to @arcoast for documenting the native Android callback. --- docs/self-hosting/authentication.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/self-hosting/authentication.md b/docs/self-hosting/authentication.md index adbd49b..1e6574c 100644 --- a/docs/self-hosting/authentication.md +++ b/docs/self-hosting/authentication.md @@ -49,10 +49,11 @@ page. Apply the override with `docker compose up -d --force-recreate typetype-se ## Redirect URI -Register this callback URL with your provider: +Register these callback URLs with your provider: ```text https:///auth/oidc/callback +dev.typetype.android://oidc/callback ``` Use your real domain (or `http://localhost:8082/auth/oidc/callback` for a local test). @@ -72,7 +73,7 @@ Create a confidential client with: | Pocket ID setting | Value | | --- | --- | -| Callback URL | `https://watch.example.com/auth/oidc/callback` | +| Callback URL | `https://watch.example.com/auth/oidc/callback` `dev.typetype.android://oidc/callback` | | Client launch URL | `https://watch.example.com/` | | Public client | off | | Requires re-authentication | off | From 7fa441881af4aaaae4598cd8702a97637a538477 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 20:46:17 +0100 Subject: [PATCH 3/8] chore: update typos action to 1.49.0 Update the spelling workflow to the current Typos release. --- .github/workflows/typos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index 35ca375..091cf08 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -19,4 +19,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v7 - name: Spell Check Repo - uses: crate-ci/typos@v1.48.0 + uses: crate-ci/typos@v1.49.0 From 7be049b6c10a8b7a0be4d92bed07327740169a1e Mon Sep 17 00:00:00 2001 From: arcoast <81871508+arcoast@users.noreply.github.com> Date: Wed, 12 Aug 2026 00:44:10 +0100 Subject: [PATCH 4/8] Document Traefik configuration for TypeType Added Traefik configuration options for TypeType container, including label-based and YAML-based setups. --- docs/self-hosting/reverse-proxy.md | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/self-hosting/reverse-proxy.md b/docs/self-hosting/reverse-proxy.md index 64cad60..032738b 100644 --- a/docs/self-hosting/reverse-proxy.md +++ b/docs/self-hosting/reverse-proxy.md @@ -69,6 +69,40 @@ The app uses WebSockets and accepts large uploads (Takeout imports). If you drop break. The settings above match what the bundled web container expects. ::: +## Option C - Traefik + +Traefik obtains and renews TLS certificates automatically. + +For a label based configuration, add these labels to your TypeType container, remember to add the TypeType container to your Traefik network and change `DOMAIN.COM` as appropriate. + +```yaml + labels: + traefik.enable: "true" + traefik.docker.network: "proxy" + traefik.http.services.typetype.loadbalancer.server.port: "80" + traefik.http.routers.typetype.service: "typetype" + traefik.http.routers.typetype.entrypoints: "websecure" + traefik.http.routers.typetype.rule: "Host(`typetype.DOMAIN.COM`)" +``` + +Alternatively, if you use a yaml based Traefik configuration. + +```yaml +http: + routers: + typetype: + entryPoints: + - websecure + rule: 'Host(`typetype.DOMAIN.COM`)' + service: typetype + + services: + typetype: + loadBalancer: + servers: + - url: https://typetype:80 +``` + ## Remote login and WebSockets Interactive YouTube login starts with a normal HTTP request, then opens a WebSocket From f757ddf2ec1ed91ba29aaa9847dcaec824a34d6e Mon Sep 17 00:00:00 2001 From: Priveetee Date: Wed, 26 Aug 2026 22:55:42 +0200 Subject: [PATCH 5/8] docs: explain remote login callback networking --- docs/self-hosting/configuration.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/self-hosting/configuration.md b/docs/self-hosting/configuration.md index f714e98..2acaa3a 100644 --- a/docs/self-hosting/configuration.md +++ b/docs/self-hosting/configuration.md @@ -145,6 +145,7 @@ and SABR endpoints. The following flag controls only interactive remote login: | --- | --- | --- | | `YOUTUBE_REMOTE_LOGIN_ENABLED` | `false` | Enables the interactive YouTube sign-in flow | | `YOUTUBE_OUTBOUND_PROXY_URL` | empty | Optional outbound proxy used for YouTube traffic | +| `YOUTUBE_REMOTE_LOGIN_CALLBACK_BASE_URL` | `http://localhost:8080` | Internal Server origin that receives the Token completion callback | | `YOUTUBE_REMOTE_LOGIN_CALLBACK_ORIGIN` | `http://typetype-server:8080` | Internal callback origin used by Token | | `YOUTUBE_REMOTE_LOGIN_TTL_MS` | `480000` | Lifetime requested by Server, clamped to 1–10 minutes | | `YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS` | `2` | Concurrent remote browser sessions, clamped to 1–8 | @@ -155,6 +156,12 @@ Keep the default callback as an internal Server URL. The browser reaches the log session through the public web origin and a WebSocket; it does not call that callback address directly. +Both callback settings must use the same internal Server origin in a custom Compose +stack. Set `YOUTUBE_REMOTE_LOGIN_CALLBACK_BASE_URL` on Server and +`YOUTUBE_REMOTE_LOGIN_CALLBACK_ORIGIN` on Token to the hostname and port that Token +can reach on the Compose network, for example `http://typetype-server:8080`. Do not +use the public web URL for either setting. + In the supported Compose file, Token keeps its own eight-minute default cap because this TTL variable is passed only to Server. Values above eight minutes therefore do not extend the effective reservation without a custom Token configuration. From 95644ef3c6eab13e7070458afb341e6e95d5ca39 Mon Sep 17 00:00:00 2001 From: Priveetee Date: Mon, 31 Aug 2026 14:19:48 +0200 Subject: [PATCH 6/8] ci: route workflows to R730 runners --- .github/workflows/deploy.yml | 2 +- .github/workflows/typos.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b63a180..ff09962 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -20,7 +20,7 @@ jobs: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: [self-hosted, Linux, X64, arko, typetype] + runs-on: [self-hosted, Linux, X64, r730, typetype] steps: - name: Checkout uses: actions/checkout@v7 diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index 091cf08..c3ac38a 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -14,7 +14,7 @@ env: jobs: spelling: name: Spell Check with Typos - runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-24.04' || fromJSON('["self-hosted","Linux","X64","arko","typetype"]') }} + runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-24.04' || fromJSON('["self-hosted","Linux","X64","r730","typetype"]') }} steps: - name: Checkout Actions Repository uses: actions/checkout@v7 From 18b3d7c17a96d4be3c47dded24afeac1da0a21b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 20:39:28 +0200 Subject: [PATCH 7/8] chore: bump crate-ci/typos from 1.49.0 to 1.50.0 (#11) Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.49.0 to 1.50.0. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.49.0...v1.50.0) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.50.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/typos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index c3ac38a..5747585 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -19,4 +19,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v7 - name: Spell Check Repo - uses: crate-ci/typos@v1.49.0 + uses: crate-ci/typos@v1.50.0 From 25ca9c8049176cd1a10f66df45fb302e39123be4 Mon Sep 17 00:00:00 2001 From: Priveetee Date: Sat, 5 Sep 2026 12:35:36 +0200 Subject: [PATCH 8/8] docs: fix Traefik TLS and network configuration --- docs/self-hosting/reverse-proxy.md | 39 +++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/docs/self-hosting/reverse-proxy.md b/docs/self-hosting/reverse-proxy.md index 032738b..98d3195 100644 --- a/docs/self-hosting/reverse-proxy.md +++ b/docs/self-hosting/reverse-proxy.md @@ -71,21 +71,43 @@ break. The settings above match what the bundled web container expects. ## Option C - Traefik -Traefik obtains and renews TLS certificates automatically. +These examples assume an existing Traefik installation with a `websecure` +entry point listening on port 443 and an +[ACME certificate resolver](https://doc.traefik.io/traefik/reference/install-configuration/tls/certificate-resolvers/acme/) +configured in Traefik's static configuration. Replace `YOUR_CERT_RESOLVER` with +that resolver's name and `watch.example.com` with your domain. Traefik uses the +resolver to obtain and renew TLS certificates; the snippets below do not create it. -For a label based configuration, add these labels to your TypeType container, remember to add the TypeType container to your Traefik network and change `DOMAIN.COM` as appropriate. +Attach Traefik and the TypeType web service (`typetype`) to the same Docker network. +The examples use an existing external network named `proxy`; replace that name +with your Traefik network. Keep the web service on its existing `default` network +as well so it can still reach the TypeType server. + +For Traefik's Docker provider, merge the following into your Compose configuration: ```yaml +services: + typetype: + networks: + - default + - proxy labels: traefik.enable: "true" traefik.docker.network: "proxy" traefik.http.services.typetype.loadbalancer.server.port: "80" traefik.http.routers.typetype.service: "typetype" traefik.http.routers.typetype.entrypoints: "websecure" - traefik.http.routers.typetype.rule: "Host(`typetype.DOMAIN.COM`)" + traefik.http.routers.typetype.rule: "Host(`watch.example.com`)" + traefik.http.routers.typetype.tls: "true" + traefik.http.routers.typetype.tls.certresolver: "YOUR_CERT_RESOLVER" + +networks: + proxy: + external: true ``` -Alternatively, if you use a yaml based Traefik configuration. +Alternatively, keep the same network attachments and use this dynamic YAML +configuration with Traefik's file provider instead of the labels: ```yaml http: @@ -93,16 +115,21 @@ http: typetype: entryPoints: - websecure - rule: 'Host(`typetype.DOMAIN.COM`)' + rule: 'Host(`watch.example.com`)' service: typetype + tls: + certResolver: YOUR_CERT_RESOLVER services: typetype: loadBalancer: servers: - - url: https://typetype:80 + - url: http://typetype:80 ``` +The web container serves plain HTTP on port 80; Traefik terminates HTTPS. +Enable the Docker or file provider in Traefik according to the example you choose. + ## Remote login and WebSockets Interactive YouTube login starts with a normal HTTP request, then opens a WebSocket