From 96da9fbae590769e1fbffd3abb352a6121b95486 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Wed, 10 Jun 2026 10:02:12 +0200 Subject: [PATCH] docs(online-inbox): KunsZitadel is server-side only; desktop uses an OIDC client flow Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/online-inbox-api-contract.md | 6 ++++++ .../specs/2026-06-10-online-inbox-design.md | 21 ++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/online-inbox-api-contract.md b/docs/online-inbox-api-contract.md index 240ae00..7f5ff1c 100644 --- a/docs/online-inbox-api-contract.md +++ b/docs/online-inbox-api-contract.md @@ -72,6 +72,12 @@ All endpoints require a valid Zitadel access token (`Authorization: Bearer **Auth (VPS/.NET):** use the in-house `KunsZitadel` nuget package (feed +> `https://git.kuns.dev/api/packages/kuns/nuget/index.json`) — call `AddKunsZitadel(...)` +> with the Zitadel authority/audience/client id to wire `JwtBearer` validation + CORS for +> the web client origin. (`KunsZitadel` is server-side token *validation* only; the desktop +> client acquires tokens via its own OIDC flow.) + | Method & path | Caller | Body | Response | |---|---|---|---| | `PUT /lists` | desktop | `[{ "id", "name" }]` — the FULL catalog | `200` | diff --git a/docs/superpowers/specs/2026-06-10-online-inbox-design.md b/docs/superpowers/specs/2026-06-10-online-inbox-design.md index 7d1302f..56222b5 100644 --- a/docs/superpowers/specs/2026-06-10-online-inbox-design.md +++ b/docs/superpowers/specs/2026-06-10-online-inbox-design.md @@ -83,8 +83,15 @@ us: Zitadel package reference. `ZitadelAuthProvider` reads the refresh token from `OnlineTokenStore`, exchanges it for an -access token via the Zitadel package, caches the access token until near expiry. **Marked -with a `// TODO(online-inbox): wire once client config is known.`** +access token, caches the access token until near expiry. **Marked with a +`// TODO(online-inbox)` until the flow is wired.** + +> **Auth correction (2026-06-10):** the `KunsZitadel` nuget package is a *server-side* +> resource-server helper (`AddKunsZitadel` → `JwtBearer` token *validation*). It belongs on +> the VPS API, NOT the desktop. The desktop must *acquire* tokens, so `ZitadelAuthProvider` +> uses a client OIDC flow — `IdentityModel.OidcClient` (auth-code + PKCE, loopback redirect) +> or the device-authorization grant — against Zitadel's OIDC endpoints, then persists the +> refresh token via `OnlineTokenStore`. ### `OnlineSyncService` (the loop) - Hosted only when `online_inbox.enabled == true` (guarded at registration). @@ -100,7 +107,7 @@ with a `// TODO(online-inbox): wire once client config is know ## UI (later increment, after VPS report) - Settings modal → new "Online Inbox" section: enable toggle, API base URL, **Sign in / - Sign out** (Zitadel browser flow via the package), connection status. + Sign out** (Zitadel browser/device flow via the OIDC client lib), connection status. - Login produces a refresh token; UI sends it to the Worker via a new hub method `SetOnlineInboxAuth(refreshToken)` → Worker writes it through `OnlineTokenStore`. - Config read/write via hub methods `GetOnlineInboxConfig` / `SetOnlineInboxConfig` @@ -126,6 +133,10 @@ with a `// TODO(online-inbox): wire once client config is know ## Open items (need the VPS report) -- Exact Zitadel authority / client id / scopes / OAuth flow (device-code vs auth-code+PKCE). +- Exact Zitadel authority/issuer, client id, scopes, and **which grant the Zitadel app is + registered for** (auth-code+PKCE with which loopback redirect URI, or device-code). This + drives the desktop OIDC client implementation. - Final API base URL. -- Whether the Zitadel package is nuget (desktop) — confirm package id + API shape. +- Desktop client OIDC library decision: `IdentityModel.OidcClient` (recommended) vs + hand-rolled device-code. (`KunsZitadel` is server-side only — see the auth correction + above; it's for the VPS API.)