feat: implement authentication flow with OAuth login page

This commit is contained in:
garionion (aider) 2025-02-26 00:11:06 +01:00
parent 10b2056954
commit 77538a7dfd
5 changed files with 146 additions and 10 deletions

View file

@ -1,9 +1,21 @@
<template>
<v-app>
<router-view />
<v-main>
<router-view />
</v-main>
</v-app>
</template>
<script lang="ts" setup>
//
import { useAuthStore } from '@/stores/auth';
import { onMounted } from 'vue';
const authStore = useAuthStore();
onMounted(async () => {
// If user has a token, fetch user info
if (authStore.isAuthenticated) {
await authStore.fetchUserInfo();
}
});
</script>

39
web/src/pages/auth.vue Normal file
View file

@ -0,0 +1,39 @@
<template>
<v-container class="fill-height">
<v-responsive class="align-center fill-height mx-auto" max-width="500">
<v-card class="pa-6" elevation="8">
<div class="text-center mb-6">
<v-img
class="mx-auto mb-6"
height="100"
src="@/assets/logo.png"
width="100"
/>
<h1 class="text-h4 font-weight-bold mb-2">Welcome</h1>
<p class="text-body-1">Please sign in to continue</p>
</div>
<v-divider class="mb-6"></v-divider>
<v-btn
block
color="primary"
size="large"
@click="login"
prepend-icon="mdi-login"
>
Sign in with OAuth
</v-btn>
</v-card>
</v-responsive>
</v-container>
</template>
<script lang="ts" setup>
const router = useRouter();
function login() {
// Redirect to the OAuth login endpoint
window.location.href = '/oauth/login';
}
</script>

View file

@ -14,6 +14,22 @@ const router = createRouter({
routes: setupLayouts(routes),
})
// Add authentication guard
router.beforeEach((to, from, next) => {
// Check if the user is authenticated
const isAuthenticated = !!localStorage.getItem('auth_token');
// If route requires auth and user is not authenticated, redirect to auth page
if (to.path !== '/auth' && !isAuthenticated) {
next('/auth');
} else if (to.path === '/auth' && isAuthenticated) {
// If user is already authenticated and tries to access auth page, redirect to home
next('/');
} else {
next();
}
});
// Workaround for https://github.com/vitejs/vite/issues/11804
router.onError((err, to) => {
if (err?.message?.includes?.('Failed to fetch dynamically imported module')) {

53
web/src/stores/auth.ts Normal file
View file

@ -0,0 +1,53 @@
// Auth store to manage authentication state
import { defineStore } from 'pinia'
export const useAuthStore = defineStore('auth', {
state: () => ({
token: localStorage.getItem('auth_token') || null,
user: null as any | null,
}),
getters: {
isAuthenticated: (state) => !!state.token,
},
actions: {
setToken(token: string) {
this.token = token;
localStorage.setItem('auth_token', token);
},
setUser(user: any) {
this.user = user;
},
logout() {
this.token = null;
this.user = null;
localStorage.removeItem('auth_token');
},
async fetchUserInfo() {
if (!this.token) return;
try {
const response = await fetch('/api/v1/health', {
headers: {
'Authorization': `Bearer ${this.token}`
}
});
if (response.ok) {
const data = await response.json();
this.setUser(data.user);
} else {
// If token is invalid, logout
this.logout();
}
} catch (error) {
console.error('Failed to fetch user info:', error);
this.logout();
}
}
}
})