From 9867bda94916ea1a6197af1ac7f4c4a64aeae462 Mon Sep 17 00:00:00 2001 From: vegard Date: Sun, 15 Mar 2026 02:00:11 +0100 Subject: [PATCH] Fiks Authentik OIDC: bruk sub-claim som bruker-ID, fjern debug-logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Authentik sin OIDC sub-claim er en SHA256-hash, ikke PostgreSQL UUID. @auth/sveltekit sin interne user.id er en annen UUID som ikke matcher. Løsning: lagre profile.sub som authentik_sub i JWT-tokenet og bruk den som session.user.id. Ny erfaringsfil: docs/erfaringer/authentik_oidc.md Co-Authored-By: Claude Opus 4.6 --- docs/erfaringer/README.md | 1 + docs/erfaringer/authentik_oidc.md | 52 +++++++++++++++++++++++++++++++ migrations/seed_dev.sql | 4 +-- web/src/hooks.server.ts | 1 - web/src/lib/server/auth.ts | 6 ++-- 5 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 docs/erfaringer/authentik_oidc.md diff --git a/docs/erfaringer/README.md b/docs/erfaringer/README.md index 2381e8a..b58ed2e 100644 --- a/docs/erfaringer/README.md +++ b/docs/erfaringer/README.md @@ -11,6 +11,7 @@ Formålet er å treffe raskere blink med neste komponent. Hver fil dekker én te | `svelte5_reaktivitet.md` | Svelte 5 $state, SSR, reaktivitet gjennom funksjoner | | `spacetimedb_integrasjon.md` | SDK-konvensjoner, TypeScript-bindings, BigInt, tilkobling | | `adapter_moenster.md` | Adapter/factory for PG↔SpacetimeDB, hybrid-tilnærming | +| `authentik_oidc.md` | Authentik sub-claim format, @auth/sveltekit JWT-quirks | ## Retningslinjer diff --git a/docs/erfaringer/authentik_oidc.md b/docs/erfaringer/authentik_oidc.md new file mode 100644 index 0000000..e71d3e0 --- /dev/null +++ b/docs/erfaringer/authentik_oidc.md @@ -0,0 +1,52 @@ +# Erfaring: Authentik OIDC-integrasjon + +## 1. `profile.sub` er IKKE Authentik sin PostgreSQL-UUID + +Authentik sin OIDC `sub`-claim er en **SHA256-hash**, ikke UUID-kolonnen fra `authentik_core_user`. Eksempel: + +| Felt | Verdi | +|---|---| +| Authentik DB `uuid` | `0ac94e00-015b-4e78-9f32-269fa6ce3f44` | +| OIDC `sub` claim | `6af61f43c6647a237cbb381ee7788376a9bc20299c2c06281d9954d763e854f0` | + +Bruk **alltid** `sub`-verdien fra OIDC som nøkkel i `users.authentik_id`. For å finne den riktige verdien for en bruker: logg inn og les `profile.sub` fra callback, eller sjekk JWT-tokenet. + +## 2. `@auth/sveltekit` sin `user.id` er IKKE `profile.sub` + +`@auth/sveltekit` genererer sin egen interne UUID for `user.id` i JWT. Denne overlever ikke mellom sesjoner og matcher ingenting i vår database. + +For å bruke Authentik `sub` som bruker-ID: + +```typescript +callbacks: { + jwt({ token, user, profile }) { + if (user) token.id = user.id; + if (profile?.sub) token.authentik_sub = profile.sub; + return token; + }, + session({ session, token }) { + if (session.user) { + // Bruk Authentik sub, IKKE token.id + session.user.id = (token.authentik_sub ?? token.id) as string; + } + return session; + } +} +``` + +`profile` er kun tilgjengelig i JWT-callbacken ved innlogging (ikke ved token-refresh), derfor må `authentik_sub` lagres i tokenet. + +**Referanse:** `web/src/lib/server/auth.ts` + +## 3. Redirect-URI i Authentik + +`@auth/sveltekit` bruker callback-URL `https:///auth/callback/`. For oss: `https://sidelinja.org/auth/callback/authentik`. + +Denne MÅ være registrert som redirect-URI i Authentik sin OAuth2-provider. Verifiser via: + +```sql +SELECT _redirect_uris FROM authentik_providers_oauth2_oauth2provider +WHERE client_id = ''; +``` + +**Tips:** Legg til en regex-variant for lokal utvikling: `http://localhost:\d+/auth/callback/authentik` med `matching_mode: "regex"`. diff --git a/migrations/seed_dev.sql b/migrations/seed_dev.sql index f13284c..1514f3f 100644 --- a/migrations/seed_dev.sql +++ b/migrations/seed_dev.sql @@ -10,12 +10,12 @@ INSERT INTO workspaces (id, name, slug) VALUES -- Vegard (Authentik sub claim + dev-user alias) INSERT INTO users (authentik_id, display_name) VALUES - ('f0c628bf-2dde-42a9-86f9-6a308248a38f', 'Vegard Nøtnæs'), + ('6af61f43c6647a237cbb381ee7788376a9bc20299c2c06281d9954d763e854f0', 'Vegard Nøtnæs'), ('dev-user-1', 'Vegard (dev)'); -- Koble begge bruker-IDer til workspace INSERT INTO workspace_members (workspace_id, user_id, role) VALUES - ('a0000000-0000-0000-0000-000000000001', 'f0c628bf-2dde-42a9-86f9-6a308248a38f', 'owner'), + ('a0000000-0000-0000-0000-000000000001', '6af61f43c6647a237cbb381ee7788376a9bc20299c2c06281d9954d763e854f0', 'owner'), ('a0000000-0000-0000-0000-000000000001', 'dev-user-1', 'owner'); -- Workspace-rot-node (parent for workspace-level channels) diff --git a/web/src/hooks.server.ts b/web/src/hooks.server.ts index c517566..1289665 100644 --- a/web/src/hooks.server.ts +++ b/web/src/hooks.server.ts @@ -28,7 +28,6 @@ const workspaceHandle: Handle = async ({ event, resolve }) => { const user = session?.user; if (user?.id) { - console.log('[workspace] user.id:', user.id, 'user.name:', user.name); event.locals.user = { id: user.id, name: user.name ?? '', diff --git a/web/src/lib/server/auth.ts b/web/src/lib/server/auth.ts index 0d706c4..aaecf2d 100644 --- a/web/src/lib/server/auth.ts +++ b/web/src/lib/server/auth.ts @@ -16,7 +16,6 @@ const authentik: Provider = { clientId: env.AUTHENTIK_CLIENT_ID, clientSecret: env.AUTHENTIK_CLIENT_SECRET, profile(profile) { - console.log('[authentik] profile sub:', profile.sub, 'name:', profile.name); return { id: profile.sub, name: profile.name ?? profile.preferred_username, @@ -55,15 +54,14 @@ export const { handle, signIn, signOut } = SvelteKitAuth({ if (profile?.sub) { token.authentik_sub = profile.sub; } - console.log('[jwt] token.id:', token.id, 'token.sub:', token.sub, 'token.authentik_sub:', token.authentik_sub, 'user?.id:', user?.id); return token; }, session({ session, token }) { if (session.user) { - // Bruk Authentik sub som user.id for å matche users-tabellen + // Authentik sub er nøkkelen i users-tabellen. + // token.id er @auth/sveltekit sin interne UUID — ikke brukbar. session.user.id = (token.authentik_sub ?? token.id) as string; } - console.log('[session] user.id:', session.user?.id); return session; } }