From 765cfe803f69fb41f3ee47aecc7d209221f401a0 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Fri, 12 Jun 2026 21:00:33 +0000 Subject: [PATCH 1/2] tripit: tripit-app provider issues sub = user email (hybrid-auth identity fix) Review of tripit slice #50 caught that the provider's default sub_mode (hashed_user_id) would make Shell JWTs carry a sub that never matches the email-keyed prod user rows - first app login would either 500 in placeholder reconciliation or split the user's identity. sub_mode = user_email makes bearer and forward-auth resolve the same row. Part of the Android APK work (tripit #50). Co-Authored-By: Claude Fable 5 --- stacks/tripit/authentik.tf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stacks/tripit/authentik.tf b/stacks/tripit/authentik.tf index c6aa1a2c..6b2a9921 100644 --- a/stacks/tripit/authentik.tf +++ b/stacks/tripit/authentik.tf @@ -51,6 +51,11 @@ resource "authentik_provider_oauth2" "tripit_app" { name = "tripit-app" client_id = "tripit-app" client_type = "public" + # sub = the user's EMAIL, not the default hashed_user_id: tripit prod users + # are email-keyed (forwardauth provisioned id == email), and the backend's + # hybrid bearer arm must resolve the SAME user row, not mint a hash-keyed + # twin (review finding, tripit #50). + sub_mode = "user_email" authorization_flow = data.authentik_flow.default_authorization_implicit_consent.id invalidation_flow = data.authentik_flow.default_provider_invalidation.id From 42cd7d827244b79efcee1e87a5862bf2c6e6f902 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Fri, 12 Jun 2026 21:16:14 +0000 Subject: [PATCH 2/2] tripit: flip AUTH_MODE to hybrid + OTA bundle env (Android Shell live) The 81a816f7 image (hybrid auth + OTA endpoints) is rolled out, so the env can flip: AUTH_MODE=hybrid with the tripit-app OIDC knobs makes the bearer-only tripit-api host actually authenticate Shell logins (browser cookie path unchanged); BUNDLE_PUBLIC_BASE pins the signed OTA zip URLs to that host; BUNDLE_TOKEN_SECRET joins the tripit-secrets ES (value already written to Vault secret/tripit). Part of the Android APK work (tripit #50/#51). Co-Authored-By: Claude Fable 5 --- stacks/tripit/main.tf | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/stacks/tripit/main.tf b/stacks/tripit/main.tf index f1748bb6..355a0314 100644 --- a/stacks/tripit/main.tf +++ b/stacks/tripit/main.tf @@ -30,12 +30,22 @@ locals { # (keys via the tripit-secrets ExternalSecret), WEATHER_PROVIDER=openmeteo, # GEOCODER_PROVIDER=openmeteo, PUSH_PROVIDER=webpush. LLM_MODE=fake and # MAIL_INGEST_ENABLED=false here (the ingest-plans CronJob overrides both). - # AUTH_MODE=forwardauth: the backend trusts the Authentik-injected - # X-authentik-email header (forward-auth at the ingress). STORAGE_DIR points - # at the RWX NFS PVC — the app's default ./var is not writable by the - # non-root user. + # AUTH_MODE=hybrid (tripit ADR-0017, image >= 81a816f7): a Bearer JWT from + # the tripit-app Authentik provider wins (validated in-app against OIDC_*); + # otherwise the backend trusts the Authentik-injected X-authentik-email + # header exactly as forwardauth did (browser path unchanged; the tripit-api + # ingress strips inbound X-authentik-* so the fallback can't be spoofed). + # STORAGE_DIR points at the RWX NFS PVC — the app's default ./var is not + # writable by the non-root user. app_env = { - AUTH_MODE = "forwardauth" + AUTH_MODE = "hybrid" + OIDC_ISSUER = "https://authentik.viktorbarzin.me/application/o/tripit-app/" + OIDC_JWKS_URL = "https://authentik.viktorbarzin.me/application/o/tripit-app/jwks/" + OIDC_AUDIENCE = "tripit-app" + # OTA Web bundles (ADR-0014): the signed zip URL must point at the + # bearer-only host — the in-app request-derived base would be wrong + # behind the proxy (uvicorn doesn't trust forwarded headers). + BUNDLE_PUBLIC_BASE = "https://tripit-api.viktorbarzin.me" SERVE_FRONTEND_DIR = "/app/frontend_build" STORAGE_DIR = "/data/documents" PERSONAL_STORAGE_DIR = "/data/personal-documents" @@ -187,6 +197,9 @@ resource "kubernetes_manifest" "external_secret" { { secretKey = "VAPID_PRIVATE_KEY", remoteRef = { key = "tripit", property = "VAPID_PRIVATE_KEY" } }, { secretKey = "VAPID_SUBJECT", remoteRef = { key = "tripit", property = "VAPID_SUBJECT" } }, { secretKey = "CALENDAR_TOKEN_SECRET", remoteRef = { key = "tripit", property = "CALENDAR_TOKEN_SECRET" } }, + # HMAC secret signing the short-lived OTA Web-bundle zip URLs (ADR-0014 + # addendum; the Shell's native downloader can't send auth headers). + { secretKey = "BUNDLE_TOKEN_SECRET", remoteRef = { key = "tripit", property = "BUNDLE_TOKEN_SECRET" } }, { secretKey = "DOCUMENT_ENCRYPTION_KEY", remoteRef = { key = "tripit", property = "DOCUMENT_ENCRYPTION_KEY" } }, { secretKey = "IMAP_PASSWORD", remoteRef = { key = "tripit", property = "IMAP_PASSWORD" } }, # spam@viktorbarzin.me password — used only by the ingest-plans CronJob