// Nuxt 3 configuration for Dezky portal // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ compatibilityDate: '2026-01-01', devtools: { enabled: true }, modules: ['nuxt-oidc-auth'], css: ['~/assets/styles/tokens.css', '~/assets/styles/base.css'], // Auto-import from the shared packages/ui workspace in addition to the // app's own components/. /shared-packages is bind-mounted in // docker-compose.yml — outside containers the same files live at // /packages/ui/components/. The local dir keeps the default // directory-based prefix (so components/partner/InviteTeammateModal.vue // stays ); the shared dir uses no prefix so // CountrySelect.vue is just . components: [ '~/components', { path: '/shared-packages/ui/components', pathPrefix: false }, ], app: { head: { link: [ { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }, { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Inter+Tight:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap', }, ], }, }, runtimeConfig: { mongodbUri: process.env.MONGODB_URI, apiBase: process.env.NUXT_API_BASE, public: { authUrl: process.env.NUXT_PUBLIC_AUTH_URL, portalUrl: process.env.NUXT_PUBLIC_PORTAL_URL, }, }, oidc: { defaultProvider: 'oidc', session: { expirationCheck: true, automaticRefresh: true, }, middleware: { globalMiddlewareEnabled: true, // Unauthenticated users land directly on the Authentik login flow. // Authentik is Dezky-branded and serves as the single sign-on entry // point for every Dezky app (portal, OCIS files, mail, chat). Direct // navigation to auth.dezky.local or the post-login dashboard // (/if/user/) is short-circuited by a Traefik middleware on the // authentik service that redirects to app.dezky.local — see // infrastructure/docker-compose/docker-compose.yml. customLoginPage: false, }, providers: { // Generic OIDC against our Authentik instance (provider preset key MUST be one of // apple, auth0, cognito, entra, github, keycloak, logto, microsoft, oidc, paypal, zitadel). oidc: { // The root .env uses PORTAL_OIDC_* (operator uses OPERATOR_OIDC_*) so // both apps can share one .env. docker-compose remaps these to // NUXT_OIDC_* per-container; locally we just read them directly. clientId: process.env.PORTAL_OIDC_CLIENT_ID || process.env.NUXT_OIDC_CLIENT_ID || '', clientSecret: process.env.PORTAL_OIDC_CLIENT_SECRET || process.env.NUXT_OIDC_CLIENT_SECRET || '', redirectUri: process.env.NUXT_OIDC_REDIRECT_URI || 'https://app.dezky.local/auth/oidc/callback', authorizationUrl: 'https://auth.dezky.local/application/o/authorize/', tokenUrl: 'https://auth.dezky.local/application/o/token/', userInfoUrl: 'https://auth.dezky.local/application/o/userinfo/', // Logout is handled by our custom /api/auth/sign-out endpoint, not the // module's RP-initiated chain. Authentik 2025.10 doesn't reliably // honor `post_logout_redirect_uri` from the provider invalidation // flow, so we end the local session ourselves and bounce to a // Dezky-branded /signed-out page that fires Authentik's end-session // in a hidden iframe for a clean IdP logout in the background. logoutUrl: '', // Discovery URL — used by id_token validation to fetch JWKS + issuer openIdConfiguration: 'https://auth.dezky.local/application/o/dezky-portal/.well-known/openid-configuration', scope: ['openid', 'profile', 'email', 'groups'], userNameClaim: 'preferred_username', responseType: 'code', grantType: 'authorization_code', pkce: true, // Authentik's access tokens aren't always parseable as JWT — skip strict parsing skipAccessTokenParsing: true, // Expose access token in the server-side session so Nitro route handlers can // forward it to platform-api. Token never reaches the browser. exposeAccessToken: true, // ALSO expose the id_token — needed so the logout handler can populate // `id_token_hint` on the RP-initiated logout URL. Without it Authentik // can't verify the request comes from a known session and falls back // to its "You've logged out" confirmation page. exposeIdToken: true, }, }, }, vite: { server: { hmr: { protocol: 'wss', clientPort: 443, }, // Vite 7's strict allowedHosts blocks anything not in this list with a // plaintext 403. We serve the portal behind Traefik on app.dezky.local. allowedHosts: ['app.dezky.local'], }, }, nitro: { routeRules: { '/api/**': { cors: true }, }, // Persist nuxt-oidc-auth's session store on disk so HMR / restarts don't // sign out everyone in dev. Memory driver (the default) is fine in prod // when there's one long-running container per instance. storage: { oidc: { driver: 'fs', base: '.nuxt/oidc-store' }, }, }, })