Files
dezky/apps/operator/nuxt.config.ts
T
Ronni Baslund 0840efb759 fix(operator,portal): env-driven sign-out URLs + host labels (no more .local in prod)
Operator sign-out hardcoded the dev Authentik end-session URL, so prod
logout landed on auth.dezky.local. Mirror the portal's env-driven pattern
(NUXT_PUBLIC_AUTH_URL/NUXT_PUBLIC_OPERATOR_URL with .local fallbacks).
Expose authUrl/operatorUrl via public runtimeConfig and use them for the
Authentik admin links and the cosmetic host labels (sidebar, eyebrows,
auth-page hints). Portal: signed-out + webmail copy now derive their hosts
from runtime config (new public.mailUrl, NUXT_PUBLIC_MAIL_URL in prod).
2026-06-10 19:51:25 +02:00

118 lines
4.4 KiB
TypeScript

// Nuxt 3 configuration for the Dezky operator portal.
// Separate app from apps/portal — different OAuth client, different cookies,
// different domain, stricter authorization. See docs/OPERATOR-PLAN.md.
// Base URLs are environment-driven so one build runs in dev (.local) and
// production (.eu) — same approach as apps/portal. Set at BUILD (CI) and
// RUNTIME (fleet/apps/operator.yaml + operator-secrets); the .local defaults
// keep local dev working with no env.
const AUTH_URL = (process.env.NUXT_PUBLIC_AUTH_URL || 'https://auth.dezky.local').replace(/\/$/, '')
const OPERATOR_URL = (process.env.NUXT_PUBLIC_OPERATOR_URL || 'https://operator.dezky.local').replace(/\/$/, '')
const OPERATOR_OIDC_APP_SLUG = process.env.OPERATOR_OIDC_APP_SLUG || 'dezky-operator'
export default defineNuxtConfig({
compatibilityDate: '2026-01-01',
devtools: { enabled: true },
modules: ['nuxt-oidc-auth'],
runtimeConfig: {
public: {
// Overridable at runtime via NUXT_PUBLIC_AUTH_URL / NUXT_PUBLIC_OPERATOR_URL
// (both set in production). Used for Authentik links and host labels.
authUrl: AUTH_URL,
operatorUrl: OPERATOR_URL,
},
},
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
// <repo>/packages/ui/components/. The local dir keeps the default
// directory-based prefix; the shared dir uses no prefix so
// CountrySelect.vue is just <CountrySelect>.
components: [
'~/components',
{ path: '/shared-packages/ui/components', pathPrefix: false },
],
app: {
head: {
htmlAttrs: { 'data-theme': 'dark' },
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',
},
],
},
},
oidc: {
defaultProvider: 'oidc',
session: {
expirationCheck: true,
automaticRefresh: true,
},
middleware: {
globalMiddlewareEnabled: true,
customLoginPage: true,
},
providers: {
// Generic OIDC against the dezky-operator Authentik client. Same shape
// as the customer portal's config but pointed at a different provider
// and a different audience.
oidc: {
clientId: process.env.NUXT_OIDC_CLIENT_ID || '',
clientSecret: process.env.NUXT_OIDC_CLIENT_SECRET || '',
redirectUri: process.env.NUXT_OIDC_REDIRECT_URI || `${OPERATOR_URL}/auth/oidc/callback`,
authorizationUrl: `${AUTH_URL}/application/o/authorize/`,
tokenUrl: `${AUTH_URL}/application/o/token/`,
userInfoUrl: `${AUTH_URL}/application/o/userinfo/`,
logoutUrl: `${AUTH_URL}/application/o/${OPERATOR_OIDC_APP_SLUG}/end-session/`,
openIdConfiguration:
`${AUTH_URL}/application/o/${OPERATOR_OIDC_APP_SLUG}/.well-known/openid-configuration`,
scope: ['openid', 'profile', 'email', 'groups'],
userNameClaim: 'preferred_username',
responseType: 'code',
grantType: 'authorization_code',
pkce: true,
skipAccessTokenParsing: true,
exposeAccessToken: true,
// Also expose id_token so /api/auth/sign-out can pass it as
// id_token_hint to Authentik's end-session endpoint. Without it
// Authentik can't identify the session to terminate and falls back
// to its own "you've logged out" confirmation page.
exposeIdToken: true,
},
},
},
vite: {
server: {
// Vite 7 added a strict host check; allow Traefik-fronted hostnames in dev
allowedHosts: ['operator.dezky.local'],
hmr: {
protocol: 'wss',
clientPort: 443,
},
},
},
nitro: {
routeRules: {
'/api/**': { cors: true },
},
// Persist nuxt-oidc-auth's session store on disk so HMR / dev-server
// restarts don't sign operators out. The default memory driver is fine
// in prod where one long-running container holds the state.
storage: {
oidc: { driver: 'fs', base: '.nuxt/oidc-store' },
},
},
})