server/web/src/hooks.server.ts
vegard 9867bda949 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>
2026-03-15 02:00:11 +01:00

66 lines
1.9 KiB
TypeScript

import type { Handle } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks';
import { env } from '$env/dynamic/private';
import { handle as authHandle } from '$lib/server/auth';
import { getWorkspaceForUser, getUserWorkspaces } from '$lib/server/db';
const WORKSPACE_COOKIE = 'sidelinja_workspace';
const isDev = env.NODE_ENV !== 'production' && !env.AUTHENTIK_CLIENT_ID;
/**
* Dev-only auth: simulerer innlogget bruker uten OIDC.
* Setter locals.auth() til å returnere en fast dev-bruker.
*/
const devAuthHandle: Handle = async ({ event, resolve }) => {
const DEV_USER = { id: 'dev-user-1', name: 'Vegard', email: 'vegard@localhost' };
// Legg til auth()-metode som hooks og layout forventer
event.locals.auth = async () => ({ user: DEV_USER, expires: '' });
return resolve(event);
};
/**
* Workspace-resolving: les aktiv workspace fra cookie,
* verifiser tilgang, og legg i locals.
*/
const workspaceHandle: Handle = async ({ event, resolve }) => {
const session = await event.locals.auth();
const user = session?.user;
if (user?.id) {
event.locals.user = {
id: user.id,
name: user.name ?? '',
email: user.email ?? '',
image: user.image ?? undefined
};
const workspaceId = event.cookies.get(WORKSPACE_COOKIE);
if (workspaceId) {
event.locals.workspace = await getWorkspaceForUser(workspaceId, user.id);
}
// Hvis ingen gyldig workspace i cookie, velg den første
if (!event.locals.workspace) {
const workspaces = await getUserWorkspaces(user.id);
if (workspaces.length > 0) {
event.locals.workspace = workspaces[0];
event.cookies.set(WORKSPACE_COOKIE, workspaces[0].id, {
path: '/',
httpOnly: true,
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 365
});
}
}
} else {
event.locals.user = null;
event.locals.workspace = null;
}
return resolve(event);
};
export const handle = isDev
? sequence(devAuthHandle, workspaceHandle)
: sequence(authHandle, workspaceHandle);