You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The app has no app-level auth by design — it trusts the reverse-proxy / SSO (Authentik forward-auth) gate, and everyone who gets through has full control: they can manage NG-login credentials, trigger scrapes, change settings, and export all data. Long-term we want differentiated access: e.g. an admin (full control), a read-only viewer (can see charts/bills but not mutate or manage credentials), and an even more restricted viewer without data export (no CSV / no bulk-PDF zip). This must not violate the "no public app-login" principle.
Proposal (long-term — design first)
Do not build an in-app login. Instead derive identity + role from the trusted SSO proxy headers the Authentik forward-auth outpost already injects (e.g. X-authentik-username, X-authentik-groups), and map groups → roles:
viewer-no-export — viewer minus CSV export and bulk-PDF download.
Enforce server-side in the API routes (never just hide buttons): a small requireRole() helper reads the forwarded header, resolves the role, and gates the relevant routes; the UI also hides controls the role can't use. Headers must only be trusted from the proxy (the app stays non-public per AGENTS.md). Role→group mapping is config (env or AppSetting), with a safe default (no header / unknown ⇒ treat as admin only when the app is in its current single-user mode, configurable — decide in design).
Acceptance criteria
A documented role model + a pure roleFromRequest(headers, config) with unit tests (header parsing, default/unknown handling).
Mutating routes (NG-login mgmt, /api/settings writes, /api/refresh) and export routes (CSV, bulk-PDF) reject below-threshold roles server-side (tested), not just hidden in the UI.
No public app-login introduced; financial data never served un-gated; behavior is unchanged for a single-admin install (back-compat default).
Security review of the header-trust path before ship.
Pointers
SSO gate / forwarded headers: compose/authentik/terraform (forward-auth provider) and SWAG authentik-location.conf (server-side, infra repo).
Export routes (CSV / bulk-PDF zip) and /api/refresh, /api/settings, NG-login routes under app/src/app/api/*.
Problem
The app has no app-level auth by design — it trusts the reverse-proxy / SSO (Authentik forward-auth) gate, and everyone who gets through has full control: they can manage NG-login credentials, trigger scrapes, change settings, and export all data. Long-term we want differentiated access: e.g. an admin (full control), a read-only viewer (can see charts/bills but not mutate or manage credentials), and an even more restricted viewer without data export (no CSV / no bulk-PDF zip). This must not violate the "no public app-login" principle.
Proposal (long-term — design first)
Do not build an in-app login. Instead derive identity + role from the trusted SSO proxy headers the Authentik forward-auth outpost already injects (e.g.
X-authentik-username,X-authentik-groups), and map groups → roles:admin— full control (current behavior).viewer— read dashboards/bills; blocked from mutations (NG-login add/remove, settings writes, manual scrape trigger).viewer-no-export—viewerminus CSV export and bulk-PDF download.Enforce server-side in the API routes (never just hide buttons): a small
requireRole()helper reads the forwarded header, resolves the role, and gates the relevant routes; the UI also hides controls the role can't use. Headers must only be trusted from the proxy (the app stays non-public per AGENTS.md). Role→group mapping is config (env orAppSetting), with a safe default (no header / unknown ⇒ treat as admin only when the app is in its current single-user mode, configurable — decide in design).Acceptance criteria
roleFromRequest(headers, config)with unit tests (header parsing, default/unknown handling)./api/settingswrites,/api/refresh) and export routes (CSV, bulk-PDF) reject below-threshold roles server-side (tested), not just hidden in the UI.Pointers
compose/authentik/terraform(forward-auth provider) and SWAGauthentik-location.conf(server-side, infra repo)./api/refresh,/api/settings, NG-login routes underapp/src/app/api/*.AGENTS.mdrules CSV export / download #3 (secrets) and Weather-normalized usage (heating/cooling degree-days) #5 (no public app-auth) are binding constraints here.