From 812048a0b57bdd0a03804bd7f21ce07d2a180fa4 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 10 Jun 2026 08:49:01 +0000 Subject: [PATCH] fix: bootstrap-gate auth before mount (krypto-kuns pattern); never call API unauthenticated Root cause: the router-guard adapter let index.vue mount and call the API before auth resolved, so auth.fetch returned a synthetic 401 (the banner) and the package's redirect-loop guard could strand the user. Now use the core ZitadelAuth and gate in an async plugin (Nuxt awaits it before mount), mirroring the working krypto-kuns app. --- app/composables/useAuth.ts | 17 +++++------------ app/pages/auth/callback.vue | 11 ++++------- app/pages/index.vue | 11 ++++++++--- app/plugins/auth.client.ts | 29 ++++++++++++++++++++++------- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/app/composables/useAuth.ts b/app/composables/useAuth.ts index b1bfbd8..a11bca6 100644 --- a/app/composables/useAuth.ts +++ b/app/composables/useAuth.ts @@ -1,17 +1,10 @@ -// Access the provided Zitadel auth instance + a small JSON helper for /api calls. +import type { ZitadelAuth } from "@kuns/zitadel-auth"; + +// Access the bootstrap-provided Zitadel auth instance + a small JSON helper for /api calls. +// By the time any component mounts, the plugin has gated auth, so `auth` is authenticated. // `auth.fetch` auto-attaches the Bearer access token. export function useAuth() { - const { $auth } = useNuxtApp() as unknown as { - $auth: { - isAuthenticated: Ref; - isLoading: Ref; - user: Ref<{ sub: string; name: string; email: string } | null>; - error: Ref; - login: () => void; - logout: () => Promise; - fetch: (url: string, init?: RequestInit) => Promise; - }; - }; + const { $auth } = useNuxtApp() as unknown as { $auth: ZitadelAuth }; async function api(path: string, init?: RequestInit): Promise { const res = await $auth.fetch(`/api${path}`, init); diff --git a/app/pages/auth/callback.vue b/app/pages/auth/callback.vue index 43a557a..3160815 100644 --- a/app/pages/auth/callback.vue +++ b/app/pages/auth/callback.vue @@ -1,11 +1,8 @@ diff --git a/app/pages/index.vue b/app/pages/index.vue index 8dd5eed..5ffd6f6 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -86,15 +86,20 @@ async function addTask() { } } -onMounted(refreshLists); +onMounted(() => { + // The auth plugin gates before mount, so this is normally authenticated. + // Safety net: if not, drive login instead of calling the API (no 401 banner). + if (auth.isAuthenticated) refreshLists(); + else auth.login(); +});