diff --git a/app.vue b/app.vue
index 09f935bbb637b61773bafe6def88f5231d51f700..8f57c2517d2174ba3b55ac3147361036ab5f31ba 100644
--- a/app.vue
+++ b/app.vue
@@ -1,6 +1,9 @@
 <template>
   <div>
-    <NuxtRouteAnnouncer />
-    <NuxtWelcome />
+    <NuxtLoadingIndicator />
+
+    <NuxtLayout>
+      <NuxtPage />
+    </NuxtLayout>
   </div>
 </template>
diff --git a/layouts/auth.vue b/layouts/auth.vue
new file mode 100644
index 0000000000000000000000000000000000000000..921b9e7f82ab4c92e6044f150d21e806108d1992
--- /dev/null
+++ b/layouts/auth.vue
@@ -0,0 +1,21 @@
+<script setup lang="ts">
+
+</script>
+
+<template>
+  <div class="h-screen flex items-center justify-center overlay">
+    <UButton
+        icon="i-heroicons-home"
+        label="Accueil"
+        to="/"
+        color="black"
+        class="absolute top-4"
+    />
+
+    <slot/>
+  </div>
+</template>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/middleware/verifyUserDoesntExists.ts b/middleware/verifyUserDoesntExists.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a4c30af4417ef622ac2c521cdecb990bd73669fa
--- /dev/null
+++ b/middleware/verifyUserDoesntExists.ts
@@ -0,0 +1,16 @@
+export default defineNuxtRouteMiddleware(async (to) => {
+    let userExists = false;
+    try {
+        await useFetch('/api/auth/userExists', {
+            onResponse: ({response}) => {
+                userExists = response._data.userExists;
+            },
+        });
+    } catch (error) {
+        console.error('Error checking if user exists', error);
+        return abortNavigation();
+    }
+    if (userExists) {
+        return navigateTo('/login');
+    }
+});
\ No newline at end of file
diff --git a/middleware/verifyUserExists.ts b/middleware/verifyUserExists.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3bff9353d040abc5d045f04fc8545e18d9a4836c
--- /dev/null
+++ b/middleware/verifyUserExists.ts
@@ -0,0 +1,16 @@
+export default defineNuxtRouteMiddleware(async (to) => {
+    let userExists = false;
+    try {
+        await useFetch('/api/auth/userExists', {
+            onResponse: ({response}) => {
+                userExists = response._data.userExists;
+            },
+        });
+    } catch (error) {
+        console.error('Error checking if user exists', error);
+        return abortNavigation();
+    }
+    if (!userExists) {
+        return navigateTo('/register');
+    }
+});
\ No newline at end of file
diff --git a/pages/admin.vue b/pages/admin.vue
new file mode 100644
index 0000000000000000000000000000000000000000..67818b9fcf8915ecaeb4ed2fafc95893dd354460
--- /dev/null
+++ b/pages/admin.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+definePageMeta({
+  middleware: 'auth'
+})
+</script>
+
+<template>
+  <div>
+    <h1>Admin Dashboard</h1>
+  </div>
+</template>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/pages/index.vue b/pages/index.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0bfc5e2d66d3d5e35c13673affcca47d606b9312
--- /dev/null
+++ b/pages/index.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+
+</script>
+
+<template>
+  <NuxtWelcome />
+</template>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/pages/login.vue b/pages/login.vue
new file mode 100644
index 0000000000000000000000000000000000000000..48c84f5a2c6ee18885004b922e12d7237c92e37f
--- /dev/null
+++ b/pages/login.vue
@@ -0,0 +1,87 @@
+<script setup lang="ts">
+import type {FormError} from "#ui/types";
+
+definePageMeta({
+  layout: 'auth',
+  middleware: 'verify-user-exists'
+});
+
+useSeoMeta({
+  title: 'Connexion',
+})
+
+const uiOptions = {
+  default: {
+    submitButton: {
+      label: 'Se connecter'
+    }
+  }
+};
+
+const formFields = [{
+  type: 'email',
+  label: 'Adresse email',
+  name: 'email',
+  placeholder: 'Entrez votre adresse email',
+  color: 'gray',
+  required: true
+}, {
+  type: 'password',
+  label: 'Mot de passe',
+  name: 'password',
+  placeholder: 'Entrez votre mot de passe',
+  color: 'gray',
+  required: true
+}];
+
+const validate = (values: any) => {
+  const errors: FormError[] = [];
+  if(!values.email) {
+    errors.push({ path: 'email', message: 'Veuillez entrer votre adresse email' });
+  }
+  if(!values.password) {
+    errors.push({ path: 'password', message: 'Veuillez entrer votre mot de passe' });
+  }
+  return errors;
+};
+
+const authStore = useAuthStore();
+const loginErrorMessage = ref<string | null>(null);
+const isLoggingIn = ref(false);
+
+async function onSubmit(data: any) {
+  isLoggingIn.value = true;
+  try {
+    await authStore.login(data.email, data.password);
+  } catch (error) {
+    console.error('Login failed', error);
+    loginErrorMessage.value = 'Identifiants incorrects';
+  } finally {
+    isLoggingIn.value = false;
+  }
+}
+</script>
+
+<template>
+  <UCard class="max-w-sm w-full">
+    <UAuthForm
+        title="Connexion"
+        description="Connectez-vous pour accéder à l'administration."
+        align="top"
+        icon="i-heroicons-user-circle"
+        :validate="validate"
+        :fields="formFields"
+        :loading="isLoggingIn"
+        :ui="uiOptions"
+        @submit="onSubmit"
+    >
+      <template #password-hint>
+        <NuxtLink to="/" class="text-primary font-medium">Mot de passe oublié ?</NuxtLink>
+      </template>
+      <template #validation v-if="loginErrorMessage !== null">
+        <UAlert color="red" icon="i-heroicons-information-circle-20-solid"
+                :title="loginErrorMessage" />
+      </template>
+    </UAuthForm>
+  </UCard>
+</template>
\ No newline at end of file
diff --git a/pages/register.vue b/pages/register.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6cb59744802660547345abfdc7954d2531d6308c
--- /dev/null
+++ b/pages/register.vue
@@ -0,0 +1,95 @@
+<script setup lang="ts">
+import type {FormError} from "#ui/types";
+definePageMeta({
+  layout: 'auth',
+  middleware: 'verify-user-doesnt-exists'
+})
+
+useSeoMeta({
+  title: 'Inscription',
+})
+
+const uiOptions = {
+  default: {
+    submitButton: {
+      label: 'Créer un compte'
+    }
+  }
+};
+
+const formFields = [{
+  name: 'name',
+  type: 'text',
+  label: 'Nom d\'utilisateur',
+  placeholder: 'Entrez votre nom d\'utilisateur',
+  required: true,
+  description: "Il ne s'agit là que d'un nom d'affichage, vous pourrez le modifier plus tard.",
+}, {
+  type: 'email',
+  label: 'Adresse email',
+  name: 'email',
+  placeholder: 'Entrez votre adresse email',
+  color: 'gray',
+  required: true,
+  description: "Soyez sûr d'entrer une adresse valide, vous serez le seul maître à bord. 👀"
+}, {
+  type: 'password',
+  label: 'Mot de passe',
+  name: 'password',
+  placeholder: 'Entrez votre mot de passe',
+  color: 'gray',
+  required: true
+}];
+
+const validate = (values: any) => {
+  const errors: FormError[] = [];
+  if (!values.email) {
+    errors.push({path: 'email', message: 'Veuillez entrer votre adresse email'});
+  }
+  if (!values.password) {
+    errors.push({path: 'password', message: 'Veuillez entrer votre mot de passe'});
+  } else {
+    if (values.password.length < 6 || values.password.length > 32) {
+      errors.push({path: 'password', message: 'Votre mot de passe doit contenir entre 6 et 32 caractères'});
+    }
+    if (!/[A-Z]/.test(values.password) || !/[a-z]/.test(values.password) || !/[0-9]/.test(values.password) || !/[^A-Za-z0-9]/.test(values.password)) {
+      errors.push({path: 'password', message: 'Votre mot de passe doit contenir au moins une majuscule, une minuscule, un chiffre et un caractère spécial'});
+    }
+  }
+  if (!values.name) {
+    errors.push({path: 'name', message: 'Veuillez entrer votre nom d\'utilisateur'});
+  } else {
+    if (values.name.length < 3 || values.name.length > 32) {
+      errors.push({path: 'name', message: 'Votre nom d\'utilisateur doit contenir entre 3 et 32 caractères'});
+    }
+  }
+  return errors;
+};
+
+const isRegisteringIn = ref(false);
+
+async function onSubmit(data: any) {
+  console.log('Registering in with data', data);
+}
+</script>
+
+<template>
+  <UCard class="max-w-sm w-full">
+    <UAuthForm
+        title="Inscription"
+        description="Bienvenue chez vous ! Créez un compte pour finaliser l'installation de votre site internet."
+        align="top"
+        icon="i-heroicons-user-circle"
+        :validate="validate"
+        :fields="formFields"
+        :loading="isRegisteringIn"
+        :ui="uiOptions"
+        @submit="onSubmit"
+    >
+    </UAuthForm>
+  </UCard>
+</template>
+
+<style scoped>
+
+</style>
\ No newline at end of file