diff --git a/README.md b/README.md index 5644377..bdd5e3f 100644 --- a/README.md +++ b/README.md @@ -139,10 +139,23 @@ services: - NODE_ENV=production - PORT=3000 - ENCRYPTION_KEY=${ENCRYPTION_KEY:-} # Recommended. Generate with: openssl rand -hex 32. If unset, falls back to data/.jwt_secret (existing installs) or auto-generates a key (fresh installs). - - ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-} # Comma-separated origins for CORS and email notification links - TZ=${TZ:-UTC} # Timezone for logs, reminders and scheduled tasks (e.g. Europe/Berlin) - LOG_LEVEL=${LOG_LEVEL:-info} # info = concise user actions; debug = verbose admin-level details - # - ALLOW_INTERNAL_NETWORK=true # Uncomment if Immich is on your local network (RFC-1918 IPs) + - ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-} # Comma-separated origins for CORS and email notification links + - FORCE_HTTPS=true # Redirect HTTP to HTTPS when behind a TLS-terminating proxy + # - COOKIE_SECURE=false # Uncomment if accessing over plain HTTP (no HTTPS). Not recommended for production. + - TRUST_PROXY=1 # Number of trusted proxies for X-Forwarded-For + # - ALLOW_INTERNAL_NETWORK=true # Uncomment if Immich or other services are on your local network (RFC-1918 IPs) + - APP_URL=${APP_URL:-} # Base URL of this instance — required when OIDC is enabled; must match the redirect URI registered with your IdP + # - OIDC_ISSUER=https://auth.example.com # OpenID Connect provider URL + # - OIDC_CLIENT_ID=trek # OpenID Connect client ID + # - OIDC_CLIENT_SECRET=supersecret # OpenID Connect client secret + # - OIDC_DISPLAY_NAME=SSO # Label shown on the SSO login button + # - OIDC_ONLY=false # Set to true to disable local password auth entirely (SSO only) + # - OIDC_ADMIN_CLAIM=groups # OIDC claim used to identify admin users + # - OIDC_ADMIN_VALUE=app-trek-admins # Value of the OIDC claim that grants admin role + # - OIDC_DISCOVERY_URL= # Override the OIDC discovery endpoint for providers with non-standard paths (e.g. Authentik) + # - DEMO_MODE=false # Enable demo mode (resets data hourly) volumes: - ./data:/app/data - ./uploads:/app/uploads @@ -265,6 +278,7 @@ trek.yourdomain.com { | `LOG_LEVEL` | `info` = concise user actions, `debug` = verbose details | `info` | | `ALLOWED_ORIGINS` | Comma-separated origins for CORS and email links | same-origin | | `FORCE_HTTPS` | Redirect HTTP to HTTPS behind a TLS-terminating proxy | `false` | +| `COOKIE_SECURE` | Set to `false` to allow session cookies over plain HTTP (e.g. accessing via IP without HTTPS). Defaults to `true` in production. **Not recommended to disable in production.** | `true` | | `TRUST_PROXY` | Number of trusted reverse proxies for `X-Forwarded-For` | `1` | | `ALLOW_INTERNAL_NETWORK` | Allow outbound requests to private/RFC-1918 IP addresses. Set to `true` if Immich or other integrated services are hosted on your local network. Loopback (`127.x`) and link-local/metadata addresses (`169.254.x`) are always blocked regardless of this setting. | `false` | | **OIDC / SSO** | | | @@ -273,6 +287,7 @@ trek.yourdomain.com { | `OIDC_CLIENT_SECRET` | OIDC client secret | — | | `OIDC_DISPLAY_NAME` | Label shown on the SSO login button | `SSO` | | `OIDC_ONLY` | Disable local password auth entirely (first SSO login becomes admin) | `false` | +| `OIDC_DISCOVERY_URL` | Override the auto-constructed OIDC discovery endpoint. Useful for providers that expose it at a non-standard path (e.g. Authentik: `https://auth.example.com/application/o/trek/.well-known/openid-configuration`) | — | | **Other** | | | | `DEMO_MODE` | Enable demo mode (hourly data resets) | `false` | diff --git a/chart/README.md b/chart/README.md index 54e8b90..87fc2fc 100644 --- a/chart/README.md +++ b/chart/README.md @@ -32,3 +32,5 @@ See `values.yaml` for more options. - `ENCRYPTION_KEY` encrypts stored secrets (API keys, MFA, SMTP, OIDC) at rest. Recommended: set via `secretEnv.ENCRYPTION_KEY` or `existingSecret`. If left empty, the server falls back automatically: existing installs use `data/.jwt_secret` (no action needed on upgrade); fresh installs auto-generate a key persisted to the data PVC. - If using ingress, you must manually keep `env.ALLOWED_ORIGINS` and `ingress.hosts` in sync to ensure CORS works correctly. The chart does not sync these automatically. - Set `env.ALLOW_INTERNAL_NETWORK: "true"` if Immich or other integrated services are hosted on a private/RFC-1918 address (e.g. a pod on the same cluster or a NAS on your LAN). Loopback (`127.x`) and link-local/metadata addresses (`169.254.x`) remain blocked regardless. +- Set `env.COOKIE_SECURE: "false"` only if your deployment has no TLS (e.g. during local testing without ingress). Session cookies require HTTPS in all other cases. +- Set `env.OIDC_DISCOVERY_URL` to override the auto-constructed OIDC discovery endpoint. Required for providers (e.g. Authentik) that expose it at a non-standard path. diff --git a/chart/templates/configmap.yaml b/chart/templates/configmap.yaml index 7e0a5a3..a7a4eb7 100644 --- a/chart/templates/configmap.yaml +++ b/chart/templates/configmap.yaml @@ -13,3 +13,9 @@ data: {{- if .Values.env.ALLOW_INTERNAL_NETWORK }} ALLOW_INTERNAL_NETWORK: {{ .Values.env.ALLOW_INTERNAL_NETWORK | quote }} {{- end }} + {{- if .Values.env.COOKIE_SECURE }} + COOKIE_SECURE: {{ .Values.env.COOKIE_SECURE | quote }} + {{- end }} + {{- if .Values.env.OIDC_DISCOVERY_URL }} + OIDC_DISCOVERY_URL: {{ .Values.env.OIDC_DISCOVERY_URL | quote }} + {{- end }} diff --git a/chart/values.yaml b/chart/values.yaml index 07164e3..2f82f4f 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -20,6 +20,10 @@ env: # ALLOW_INTERNAL_NETWORK: "false" # Set to "true" if Immich or other integrated services are hosted on a private/RFC-1918 network address. # Loopback (127.x) and link-local/metadata addresses (169.254.x) are always blocked. + # COOKIE_SECURE: "true" + # Set to "false" to allow session cookies over plain HTTP (e.g. no ingress TLS). Not recommended for production. + # OIDC_DISCOVERY_URL: "" + # Override the OIDC discovery endpoint for providers with non-standard paths (e.g. Authentik). # Secret environment variables stored in a Kubernetes Secret. diff --git a/docker-compose.yml b/docker-compose.yml index 6c2ccba..731a77c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,13 +23,15 @@ services: - LOG_LEVEL=${LOG_LEVEL:-info} # info = concise user actions; debug = verbose admin-level details - ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-} # Comma-separated origins for CORS and email notification links - FORCE_HTTPS=true # Redirect HTTP to HTTPS when behind a TLS-terminating proxy +# - COOKIE_SECURE=false # Uncomment if accessing over plain HTTP (no HTTPS). Not recommended for production. - TRUST_PROXY=1 # Number of trusted proxies (for X-Forwarded-For / real client IP) - ALLOW_INTERNAL_NETWORK=false # Set to true if Immich or other services are hosted on your local network (RFC-1918 IPs). Loopback and link-local addresses remain blocked regardless. - - OIDC_ISSUER=https://auth.example.com # OpenID Connect provider URL - - OIDC_CLIENT_ID=trek # OpenID Connect client ID - - OIDC_CLIENT_SECRET=supersecret # OpenID Connect client secret - - OIDC_DISPLAY_NAME=SSO # Label shown on the SSO login button - - OIDC_ONLY=false # Set true to disable local password auth entirely (SSO only) +# - OIDC_ISSUER=https://auth.example.com # OpenID Connect provider URL +# - OIDC_CLIENT_ID=trek # OpenID Connect client ID +# - OIDC_CLIENT_SECRET=supersecret # OpenID Connect client secret +# - OIDC_DISPLAY_NAME=SSO # Label shown on the SSO login button +# - OIDC_ONLY=false # Set true to disable local password auth entirely (SSO only) +# - OIDC_DISCOVERY_URL= # Override the OIDC discovery endpoint for providers with non-standard paths (e.g. Authentik) volumes: - ./data:/app/data - ./uploads:/app/uploads diff --git a/server/.env.example b/server/.env.example index 1dcabc0..35be0dd 100644 --- a/server/.env.example +++ b/server/.env.example @@ -10,6 +10,7 @@ LOG_LEVEL=info # info = concise user actions; debug = verbose admin-level detail ALLOWED_ORIGINS=https://trek.example.com # Comma-separated origins for CORS and email links FORCE_HTTPS=false # Redirect HTTP → HTTPS behind a TLS proxy +COOKIE_SECURE=true # Set to false to allow session cookies over HTTP (e.g. plain-IP or non-HTTPS setups). Defaults to true in production. TRUST_PROXY=1 # Number of trusted proxies for X-Forwarded-For ALLOW_INTERNAL_NETWORK=false # Allow outbound requests to private/RFC1918 IPs (e.g. Immich hosted on your LAN). Loopback and link-local addresses are always blocked. @@ -22,6 +23,6 @@ OIDC_DISPLAY_NAME=SSO # Label shown on the SSO login button OIDC_ONLY=true # Disable local password auth entirely (SSO only) OIDC_ADMIN_CLAIM=groups # OIDC claim used to identify admin users OIDC_ADMIN_VALUE=app-trek-admins # Value of the OIDC claim that grants admin role -OIDC_DISCOVERY_URL= # Override the auto-constructed discovery endpoint (e.g. Authentik: https://auth.example.com/application/o/trek/.well-known/openid-configuration) +OIDC_DISCOVERY_URL= # Override the auto-constructed OIDC discovery endpoint. Useful for providers (e.g. Authentik) that expose it at a non-standard path. Example: https://auth.example.com/application/o/trek/.well-known/openid-configuration DEMO_MODE=false # Demo mode - resets data hourly diff --git a/server/src/services/cookie.ts b/server/src/services/cookie.ts index 448e25c..2111221 100644 --- a/server/src/services/cookie.ts +++ b/server/src/services/cookie.ts @@ -3,7 +3,7 @@ import { Response } from 'express'; const COOKIE_NAME = 'trek_session'; function cookieOptions(clear = false) { - const secure = process.env.NODE_ENV === 'production' || process.env.FORCE_HTTPS === 'true'; + const secure = process.env.COOKIE_SECURE !== 'false' && (process.env.NODE_ENV === 'production' || process.env.FORCE_HTTPS === 'true'); return { httpOnly: true, secure,