Fiks Authentik OIDC: bruk sub-claim som bruker-ID, fjern debug-logging
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 <noreply@anthropic.com>
This commit is contained in:
parent
3d3c99cb0d
commit
9867bda949
5 changed files with 57 additions and 7 deletions
|
|
@ -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 |
|
| `svelte5_reaktivitet.md` | Svelte 5 $state, SSR, reaktivitet gjennom funksjoner |
|
||||||
| `spacetimedb_integrasjon.md` | SDK-konvensjoner, TypeScript-bindings, BigInt, tilkobling |
|
| `spacetimedb_integrasjon.md` | SDK-konvensjoner, TypeScript-bindings, BigInt, tilkobling |
|
||||||
| `adapter_moenster.md` | Adapter/factory for PG↔SpacetimeDB, hybrid-tilnærming |
|
| `adapter_moenster.md` | Adapter/factory for PG↔SpacetimeDB, hybrid-tilnærming |
|
||||||
|
| `authentik_oidc.md` | Authentik sub-claim format, @auth/sveltekit JWT-quirks |
|
||||||
|
|
||||||
## Retningslinjer
|
## Retningslinjer
|
||||||
|
|
||||||
|
|
|
||||||
52
docs/erfaringer/authentik_oidc.md
Normal file
52
docs/erfaringer/authentik_oidc.md
Normal file
|
|
@ -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://<domain>/auth/callback/<provider-id>`. 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 = '<din client_id>';
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tips:** Legg til en regex-variant for lokal utvikling: `http://localhost:\d+/auth/callback/authentik` med `matching_mode: "regex"`.
|
||||||
|
|
@ -10,12 +10,12 @@ INSERT INTO workspaces (id, name, slug) VALUES
|
||||||
|
|
||||||
-- Vegard (Authentik sub claim + dev-user alias)
|
-- Vegard (Authentik sub claim + dev-user alias)
|
||||||
INSERT INTO users (authentik_id, display_name) VALUES
|
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)');
|
('dev-user-1', 'Vegard (dev)');
|
||||||
|
|
||||||
-- Koble begge bruker-IDer til workspace
|
-- Koble begge bruker-IDer til workspace
|
||||||
INSERT INTO workspace_members (workspace_id, user_id, role) VALUES
|
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');
|
('a0000000-0000-0000-0000-000000000001', 'dev-user-1', 'owner');
|
||||||
|
|
||||||
-- Workspace-rot-node (parent for workspace-level channels)
|
-- Workspace-rot-node (parent for workspace-level channels)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ const workspaceHandle: Handle = async ({ event, resolve }) => {
|
||||||
const user = session?.user;
|
const user = session?.user;
|
||||||
|
|
||||||
if (user?.id) {
|
if (user?.id) {
|
||||||
console.log('[workspace] user.id:', user.id, 'user.name:', user.name);
|
|
||||||
event.locals.user = {
|
event.locals.user = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
name: user.name ?? '',
|
name: user.name ?? '',
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ const authentik: Provider = {
|
||||||
clientId: env.AUTHENTIK_CLIENT_ID,
|
clientId: env.AUTHENTIK_CLIENT_ID,
|
||||||
clientSecret: env.AUTHENTIK_CLIENT_SECRET,
|
clientSecret: env.AUTHENTIK_CLIENT_SECRET,
|
||||||
profile(profile) {
|
profile(profile) {
|
||||||
console.log('[authentik] profile sub:', profile.sub, 'name:', profile.name);
|
|
||||||
return {
|
return {
|
||||||
id: profile.sub,
|
id: profile.sub,
|
||||||
name: profile.name ?? profile.preferred_username,
|
name: profile.name ?? profile.preferred_username,
|
||||||
|
|
@ -55,15 +54,14 @@ export const { handle, signIn, signOut } = SvelteKitAuth({
|
||||||
if (profile?.sub) {
|
if (profile?.sub) {
|
||||||
token.authentik_sub = 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;
|
return token;
|
||||||
},
|
},
|
||||||
session({ session, token }) {
|
session({ session, token }) {
|
||||||
if (session.user) {
|
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;
|
session.user.id = (token.authentik_sub ?? token.id) as string;
|
||||||
}
|
}
|
||||||
console.log('[session] user.id:', session.user?.id);
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue