⚠️ Warning:
- The DB has schema changes. Backup your DB before applying the update.
- This is a beta pre-release and is intended for validation before stable release.
- Review new environment variable defaults and configuration changes below.
Security Fix: Activity Media Upload Authorization
We fixed an authorization issue affecting activity media uploads. Under certain conditions, an authenticated user could upload media to an activity they did not own.
The issue was reported responsibly by Christian Flaßkamp. Thank you for helping make Endurain safer.
Users should update to the latest release.
Environment Variables & Configuration
New Variables
ALLOW_API_KEY_QUERY_PARAM(default:False) - Allows API keys to be passed as a?api_key=query parameter. Disabled by default because query-string credentials appear in access logs and browser history. Enable only if you have integrations that cannot set custom headers.CSP_ADDITIONAL_CONNECT_SRC(default:empty) - Comma-separated list of extra origins appended to theContent-Security-Policyconnect-srcdirective. Set this when Endurain is behind a forward-auth reverse proxy (e.g. Pangolin) that redirects API calls to its own domain for session validation. Without its origin here the browser blocks the redirect with a CSP error and the app fails to load.SMTP_FROM(default:empty) - Sets the "From" address on outgoing emails. If unset, it is auto-detected (usuallySMTP_USERNAME). Set this when your provider requires a verified sender that differs from the login username (e.g. Brevo)
Changed Defaults
ALLOWED_REDIRECT_SCHEMES- Now defaults toenduraininstead of being empty. This enables OAuth redirect flows for the built-in Endurain URI scheme on mobile. If you set this explicitly, the provided list replaces the default (doesn't merge). To allow only relative paths (old behavior), set to empty:ALLOWED_REDIRECT_SCHEMES=.ENVIRONMENT-production/demonow set theSecureflag on both the refresh-token cookie and the OAuth/SSO session cookie (requires HTTPS in those environments)TRUSTED_PROXIES- now accepts hostnames in addition to IPs/CIDRs, resolved to IPs at startup and refreshed periodically
Removed
UID/GID- no longer needed. The container now runs as a fixed non-rootappuser. Useuser: "<UID>:<GID>"in docker-compose for a custom UID/GID andchownthe host bind mounts accordinglyFRONTEND_PROTOCOL- superseded byENVIRONMENT, now the single source of truth for the cookieSecureflag across login, refresh, and SSO
Frontend v2: Rebuilt on Tailwind v4 + shadcn-vue
The web frontend has been rebuilt from the ground up (#742). The legacy Bootstrap 5 app (frontend/app, v1) has been removed and v2 (frontend) is now the default served app.
Why v2 over v1:
| Area | v1 | v2 |
|---|---|---|
| Components | Options API, mixed typing | <script setup lang="ts">, fully typed
|
| API layer | Hand-written calls & types (drift-prone) | Generated client from the backend OpenAPI schema; contract drift = TypeScript error |
| Server state | Ad-hoc fetch + manual loading/error handling | TanStack Query (caching, dedupe, background refetch, cancellation) |
| UI primitives | Bootstrap JS components | shadcn-vue / reka-ui (headless, accessible) |
| Styling | Generic Bootstrap theme, hard to customize | Token-based design system, dark-mode-first |
| Tests | None | Vitest + @vue/test-utils |
| Quality gate | — | npm run check (type-check + lint + format + test)
|
| Performance | Single bundle + full Bootstrap CSS | Route-level code splitting, lazy i18n locales, smaller CSS |
| Security | — | Tokens in HTTP-only cookies, SafeHtml/DOMPurify, CSP-friendly markup |
And of course it looks better, we think.
Changes from v0.19.0-beta5
- Security Fix: Activity Media Upload Authorization #8f20cc95ddd302a727bd06e86466517c031d1fad
- Add deprecation warnings/checks for retired environment variables (
UID/GID,FRONTEND_PROTOCOL) - Recompute HR zone percentages when max heart rate or birthdate changes, fixing hidden HR zones graph for beta-channel users (#780)
- Persist sort, filters, and page to URL query params on the Activities list so browser back/forward preserves state (#779)
- Show calories/avg heart rate values when sorting the activities list by those columns (#781)
- Label the lap column per sport (Strokes for rowing/kayaking, Strides for walking/running, Revolutions for cycling) (#789)
- Add mobile app privacy policy to the docs (#785)
- Update docs for activity media upload parameters and error handling
- Clarify which language the Strava import script works in (docs) (#773)
- Dim rest laps and blank their meaningless pace (#790)
Changes from v0.19.0-beta4
- Add jump rope activity type support (backend, frontend, i18n, docs, tests) (#747)
- Add upload placeholder skeleton (
HomeActivityCardSkeleton) to the Home view while an activity is uploading - Improve distance calculation for GPX and TCX file imports
- Derive FIT distance when the session
total_distancefield is missing, using GPS track or average speed as a fallback (#766) - Compute average speed, cadence, and elevation from FIT waypoints when the session omits them (#767)
- Map
indoor_runningandindoor_cyclingFIT sub-sports correctly, fixing Apple Watch/HealthFit imports showing as "Workout"/"Ride" (#763, #764, #765) - Persist selected period and activity type filter to URL query params on the Summary Statistics page so they survive a refresh (#762)
- Include GID in
start.shlogging andchownerror messages so the suggested fix command is correct (#759) - Make
index.htmlworld-writable so customuser: "UID:GID"overrides no longer crash-loop the container (#755) - Log Garmin sync
HTTPExceptiondetail and clean up orphaned extracted files to avoid perpetual sync failures (#757) - Standardize password visibility toggles and confirm-password fields across the frontend; fix admin vs. regular account password minimum-length policy mismatch (#756)
- Update environment variable handling for secure cookies in authentication
- Enhance login flow to handle local-login override in
authGuardand display alerts correctly - Add auto-redirect to SSO and local login bypass instructions
- Fix note on personalizing the login image in the advanced getting started guide
- Update supported versions in
SECURITY.md - Bump backend dependencies
Changes from v0.19.0-beta3
- Fix issue on unit conversions from metric to imperial
Changes from v0.19.0-beta2
- New logo and a refreshed brand color palette, plus formal Brand & UX guidelines documenting the design system, typography, and component conventions for anyone contributing to the UI.
- i18n coverage expanded with Polish, Turkish, Ukrainian, Romanian, Norwegian, Danish, Finnish, Czech, Greek, Hungarian, Bulgarian, Croatian, Serbian, Slovak, Lithuanian, Latvian, and Estonian (AI-translated).
- Rebuild the frontend UI on Tailwind v4 + shadcn-vue (#742)
- Add
SMTP_FROMto fix email sender validation failure on strict providers (e.g. Brevo) (#746) - Migrate gears CRUD to Pydantic schemas and improve processing robustness (#743)
- Migrate health CRUD to Pydantic schemas and improve processing robustness (#734)
- Migrate migrations CRUD to Pydantic schemas and improve processing robustness (#715)
- Replace WebSocket URL access token with a short-lived, single-use ticket (#732)
- Add support for China accounts in Garmin Connect integration (#731)
- Fix refresh token rotation reuse detection and cleanup boundary race (#735)
- Gracefully handle Strava activities with no streams (Apple Health imports) (#736)
- Exclude zero heart rate values from average/max HR calculations (#737)
- Convert several async backend routes/CRUD (users, health, server settings) to sync; clean up unused notification/fasting code
Changes from v0.19.0-beta1
- Show sleep stage tooltip times in local timezone (#504) #733
- Restore admin user identity-provider endpoints removed in #685 (#728)
- Skip read-only computed properties in edit_user mass-assignment (#727)
- Add major.minor Docker manifest tags for version pinning (#724)
- Repair health_sleep columns left as numeric by v0.16.0 pre-release (#719)
- Fix issue on manufacturer .fit file import (#717)
- Update activity graph selector menu labels on language switch (#713) #714
- Show graph summary stats on desktop activity view (#538) #711
- Fixes bug when constructing some asset paths (#702)
- Continued type-safety and mypy-driven backend improvements #712.
Backend
- Refactored auth boundaries around IdentityService and canonical auth modules (#625).
- Consolidated auth/users boundaries and removed deprecated auth paths/properties (#625).
- Migrated MFA data model and logic toward users_mfa/auth_mfa structure (#625).
- Improved activity-stream ingestion by pre-computing HR zone percentages (#700, #693).
- Added hostname support in TRUSTED_PROXIES (#667).
- Fixed profile export/import silent data loss risk (#669).
- Improved logging handler setup to support multiple handlers (#692).
- Fixed multi-sport Garmin Connect activity retrieval query handling.
- Fixed Strava CSV gear matching by trimming trailing whitespace (#668).
- Added secret generation tooling and related backend updates.
- Continued type-safety and mypy-driven backend improvements (#679).
Frontend
- Added a new login image for version 0.19.0.
- Added explicit config error display when ENDURAIN_HOST is misconfigured (#663).
- Resolved frontend lint/format debt and dependency maintenance updates (#648).
- Added newsletter subscription form and styling updates.
Testing
- Expanded backend test coverage from about 57% to about 80% (#658).
- Added comprehensive auth module tests: identity providers, MFA workflow, token hashing, maintenance paths (#625).
- Added CI backend unit test workflow for pull requests (#653).
- Improved exception-path testing across auth and MFA flows (#685).
CI/CD and Security
- Hardened dependency supply chain and automation strategy in workflows (#670).
- Added and refined Conventional Commits validation workflow/rules.
- Updated workflow trigger strategy and PR automation (including AI review workflow).
- Improved HMAC handling in CI with Python/OpenSSL fallback behavior.
- Migrated docs workflow steps to uv and reduced redundant setup (#671).
- Enforced stricter renovate/pinning behavior: minimum release age (#689) and digest handling (#687, #681).
- Updated runner usage and workflow reliability adjustments (#688).
- Added format and lint check to CI (#630).
Docs and Maintenance
- Fixed docs references and module placement alignment with codebase structure.
- Updated feature freeze and project process documentation.
- Removed obsolete Forgejo runner docs/config remnants.
- Performed broad dependency and lint maintenance across backend/frontend (#644, #646, #654).
- Refactored test structure and removed import path hacks (#654).
Contributors
- @hugobatista
- @joaovitoriasilva
- @emon in #708, #710, #711, #714, #717, #719, #727, #728 and #733
- @SethGower in #702
- @DanyPM in #766, #789 and #790
- @waitresshydrogen in #773