nav guard and redirection
have problem with my nuxt3 app i am making middle ware like this
and i have the default layout like this
and i have the index page like this
import { useMainStore } from "~/stores/main";
export default defineNuxtRouteMiddleware(async (to, from) => {
if (process.server) return;
const MainStore = useMainStore();
if (!MainStore.AccessToken) {
return navigateTo("/auth/login");
}
const config = useRuntimeConfig();
try {
const resp = await $fetch(`${config.public.serverApi}/login`, {
method: "post",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: {
fromRefresh: true,
},
});
MainStore.Login(resp.username, resp.accessToken);
return;
} catch (e) {
console.log(e.data.message);
return navigateTo("/auth/login");
}
});
import { useMainStore } from "~/stores/main";
export default defineNuxtRouteMiddleware(async (to, from) => {
if (process.server) return;
const MainStore = useMainStore();
if (!MainStore.AccessToken) {
return navigateTo("/auth/login");
}
const config = useRuntimeConfig();
try {
const resp = await $fetch(`${config.public.serverApi}/login`, {
method: "post",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: {
fromRefresh: true,
},
});
MainStore.Login(resp.username, resp.accessToken);
return;
} catch (e) {
console.log(e.data.message);
return navigateTo("/auth/login");
}
});
<script setup></script>
<template>
<div class="relative min-h-[100dvh]">
<!-- start of bg of the auth pages -->
<div class="absolute h-full w-full">
<img src="/imgs/auth-bg.jpg" class="w-full h-full object-cover" />
<div class="w-full h-full absolute bg-primary/30 inset-0"></div>
<img
src="/imgs/logo.png"
class="absolute top-2 left-2 w-[15%] object-cover aspect-square"
/>
</div>
<!-- end of bg of the auth pages -->
<slot />
</div>
</template>
<style scoped></style>
<script setup></script>
<template>
<div class="relative min-h-[100dvh]">
<!-- start of bg of the auth pages -->
<div class="absolute h-full w-full">
<img src="/imgs/auth-bg.jpg" class="w-full h-full object-cover" />
<div class="w-full h-full absolute bg-primary/30 inset-0"></div>
<img
src="/imgs/logo.png"
class="absolute top-2 left-2 w-[15%] object-cover aspect-square"
/>
</div>
<!-- end of bg of the auth pages -->
<slot />
</div>
</template>
<style scoped></style>
<script setup>
definePageMeta({
middleware: ["require-auth"],
// or middleware: 'auth'
});
</script>
<template>
<div></div>
</template>
<script setup>
definePageMeta({
middleware: ["require-auth"],
// or middleware: 'auth'
});
</script>
<template>
<div></div>
</template>
1 Reply
and i have the page called /auth/login like this
with the middle ware above applied to it but when the navigation guard redirect me to the /auth/login all the page style got broken and gives me err hydration missmatch on the console
it only works fine if i make my /auth/login page as ClientOnly page
and if u will ask why i am making the middle ware only on client its bec the /login route of backend uses cookies which isnt availible for nuxt server it only availble on client browser
if i make the middle ware on both client and server this problem wil be solver but the backend server will always return back with 401 or 400 bec the cookies wil be empty and doesnt contain the jwt
may be force name the layout ?
<script setup>
import { useMainStore } from "~/stores/main";
const MainStore = useMainStore();
const toast = useToast();
const state = reactive({
username: undefined,
password: undefined,
});
const ShowPassword = ref(false);
const Loading = ref(false);
async function onSubmit(event) {
const Config = useRuntimeConfig();
if (Loading.value) return;
Loading.value = true;
try {
const response = await $fetch(`${Config.public.serverApi}/login`, {
method: "post",
credentials: "include",
body: {
username: event.data.username,
password: event.data.password,
},
});
MainStore.Login(event.data.username, response.accessToken);
toast.add({
icon: "i-heroicons-check-badge",
description: "Logged In Successfully Redirecting To Home Page",
title: "Success",
timeout: 5000,
color: "green",
callback: () => {
navigateTo("/");
},
});
} catch (e) {
toast.add({
icon: "ic:baseline-sms-failed",
description: e.data.message,
title: "Failed ...",
color: "red",
timeout: 5000,
});
} finally {
Loading.value = false;
}
}
</script>
<script setup>
import { useMainStore } from "~/stores/main";
const MainStore = useMainStore();
const toast = useToast();
const state = reactive({
username: undefined,
password: undefined,
});
const ShowPassword = ref(false);
const Loading = ref(false);
async function onSubmit(event) {
const Config = useRuntimeConfig();
if (Loading.value) return;
Loading.value = true;
try {
const response = await $fetch(`${Config.public.serverApi}/login`, {
method: "post",
credentials: "include",
body: {
username: event.data.username,
password: event.data.password,
},
});
MainStore.Login(event.data.username, response.accessToken);
toast.add({
icon: "i-heroicons-check-badge",
description: "Logged In Successfully Redirecting To Home Page",
title: "Success",
timeout: 5000,
color: "green",
callback: () => {
navigateTo("/");
},
});
} catch (e) {
toast.add({
icon: "ic:baseline-sms-failed",
description: e.data.message,
title: "Failed ...",
color: "red",
timeout: 5000,
});
} finally {
Loading.value = false;
}
}
</script>
<template>
<div
class="bg-neutral-800/50 w-[40%] min-h-[60%] z-20 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 flex flex-col items-center justify-center rounded-md gap-8"
>
<h3>Login</h3>
<UForm
:validate="validate"
:state="state"
class="flex flex-col items-center justify-center gap-4 w-full"
@submit="onSubmit"
>
<UFormGroup label="Username" name="username" class="w-[80%]">
<UInput v-model="state.username" />
</UFormGroup>
<UFormGroup label="Password" name="password" class="w-[80%]">
<UInput
v-model="state.password"
:type="ShowPassword ? 'text' : 'password'"
:ui="{ icon: { trailing: { pointer: '' } } }"
>
<template #trailing>
<UButton
v-show="state.password && state.password != ''"
color="gray"
variant="link"
icon="ph:eye-light"
:padded="false"
@click="ShowPassword = !ShowPassword"
/>
</template>
</UInput>
</UFormGroup>
<UButton size="xl" type="submit" :lodaing="Loading">
Login
</UButton>
</UForm>
<p class="flex items-center small-text">
Don't have account ?
<UButton
color="primary"
variant="link"
to="/auth/register"
class="small-text"
>
Create New One
</UButton>
</p>
</div>
</template>
<template>
<div
class="bg-neutral-800/50 w-[40%] min-h-[60%] z-20 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 flex flex-col items-center justify-center rounded-md gap-8"
>
<h3>Login</h3>
<UForm
:validate="validate"
:state="state"
class="flex flex-col items-center justify-center gap-4 w-full"
@submit="onSubmit"
>
<UFormGroup label="Username" name="username" class="w-[80%]">
<UInput v-model="state.username" />
</UFormGroup>
<UFormGroup label="Password" name="password" class="w-[80%]">
<UInput
v-model="state.password"
:type="ShowPassword ? 'text' : 'password'"
:ui="{ icon: { trailing: { pointer: '' } } }"
>
<template #trailing>
<UButton
v-show="state.password && state.password != ''"
color="gray"
variant="link"
icon="ph:eye-light"
:padded="false"
@click="ShowPassword = !ShowPassword"
/>
</template>
</UInput>
</UFormGroup>
<UButton size="xl" type="submit" :lodaing="Loading">
Login
</UButton>
</UForm>
<p class="flex items-center small-text">
Don't have account ?
<UButton
color="primary"
variant="link"
to="/auth/register"
class="small-text"
>
Create New One
</UButton>
</p>
</div>
</template>