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.
This commit is contained in:
@@ -1,19 +1,34 @@
|
||||
import { useZitadelAuth } from "@kuns/zitadel-auth/vue";
|
||||
import { ZitadelAuth } from "@kuns/zitadel-auth";
|
||||
|
||||
// Wire the framework-agnostic Zitadel OIDC client to Nuxt's router (client-only SPA).
|
||||
// Provides `$auth` (reactive state + login/logout/fetch). The adapter installs a
|
||||
// router guard that redirects unauthenticated users to the Zitadel hosted login.
|
||||
export default defineNuxtPlugin(() => {
|
||||
// Bootstrap-gate auth BEFORE the app mounts (mirrors the working krypto-kuns pattern):
|
||||
// Nuxt awaits async plugins before mounting, so we await init() and, if unauthenticated,
|
||||
// redirect to Zitadel and hold the mount — the app never renders (and never calls the API)
|
||||
// while unauthenticated. This avoids the router-guard mount race that produced a 401 flash.
|
||||
export default defineNuxtPlugin(async () => {
|
||||
const cfg = useRuntimeConfig().public;
|
||||
const scopes = ["openid", "profile", "email"];
|
||||
if (cfg.zitadelProjectId) {
|
||||
// Force the project id into the access token's `aud` for backend validation.
|
||||
// Put the project id into the access token's `aud` for backend validation.
|
||||
scopes.push(`urn:zitadel:iam:org:project:id:${cfg.zitadelProjectId}:aud`);
|
||||
}
|
||||
const auth = useZitadelAuth(useRouter() as never, {
|
||||
|
||||
const auth = new ZitadelAuth({
|
||||
clientId: cfg.zitadelClientId as string,
|
||||
issuer: cfg.zitadelIssuer as string,
|
||||
scopes,
|
||||
// Bootstrap gate issues at most one redirect per load, so a real loop never happens;
|
||||
// raise the loop-guard ceiling so repeated manual reloads can't strand the user.
|
||||
maxRedirects: 100,
|
||||
});
|
||||
|
||||
const onCallback = window.location.pathname.endsWith("/auth/callback");
|
||||
await auth.init();
|
||||
|
||||
if (!auth.isAuthenticated && !onCallback) {
|
||||
auth.login();
|
||||
// Hold the mount while the browser navigates to the Zitadel login.
|
||||
await new Promise(() => {});
|
||||
}
|
||||
|
||||
return { provide: { auth } };
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user