diff --git a/frontend/src/lib/auth.ts b/frontend/src/lib/auth.ts new file mode 100644 index 0000000..b3e930b --- /dev/null +++ b/frontend/src/lib/auth.ts @@ -0,0 +1,28 @@ +interface JWTPayload { + userId: number; + username: string; + role: string; + exp: number; + iat: number; +} + +export function decodeJWT(token: string): JWTPayload | null { + try { + const parts = token.split('.'); + if (parts.length !== 3) return null; + + const payload = parts[1]; + const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/')); + return JSON.parse(decoded); + } catch { + return null; + } +} + +export function isTokenValid(token: string): boolean { + const payload = decodeJWT(token); + if (!payload) return false; + + const now = Math.floor(Date.now() / 1000); + return payload.exp > now; +} diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte index 9f52f89..f50f2bf 100644 --- a/frontend/src/routes/+layout.svelte +++ b/frontend/src/routes/+layout.svelte @@ -2,9 +2,10 @@ import { page } from '$app/stores'; import { goto } from '$app/navigation'; import { onMount } from 'svelte'; + import { decodeJWT, isTokenValid } from '$lib/auth'; let { children } = $props(); - let user: { username?: string; email?: string; role?: string } | null = $state(null); + let user: { userId?: number; username?: string; role?: string } | null = $state(null); let selectedDomain = $state(null); let loading = $state(true); let showDropdown = $state(false); @@ -47,35 +48,25 @@ } }); - async function checkAuth() { + function checkAuth() { const token = localStorage.getItem('token'); - if (!token) { + if (!token || !isTokenValid(token)) { goto('/auth/login'); return; } - try { - const res = await fetch('/api/auth/me', { - headers: { Authorization: `Bearer ${token}` } - }); - - if (!res.ok) { - goto('/auth/login'); - return; - } - - const data = await res.json(); - user = data.data; - - if (user?.role !== 'admin') { - goto('/auth/dashboard'); - return; - } - } catch { + const payload = decodeJWT(token); + if (!payload) { goto('/auth/login'); - } finally { - loading = false; + return; } + + user = { + userId: payload.userId, + username: payload.username, + role: payload.role + }; + loading = false; } function logout() { @@ -111,7 +102,7 @@
{#if showDropdown} diff --git a/frontend/src/routes/domains/+page.svelte b/frontend/src/routes/domains/+page.svelte index d57a361..a6aa547 100644 --- a/frontend/src/routes/domains/+page.svelte +++ b/frontend/src/routes/domains/+page.svelte @@ -1,4 +1,6 @@

Domains

- {#if isAdmin()} + {#if isAdmin} {/if}
-{#if user && !isAdmin() && user.domains.length > 0} -

Your Domains

-
- {#each user.domains as domainName} - - {domainName} - Manage → - - {/each} -
-{/if} - {#if loading}

Loading...

-{:else if isAdmin() && domains.length === 0} +{:else if domains.length === 0}

No domains configured yet.

-{:else if isAdmin()} -

All Domains

+{:else} +

Domains