From 81403355184092306105ca6418cc986c2f2eafc2 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 28 May 2025 02:17:00 +0200 Subject: [PATCH 01/35] feat: disable ssr to enable client-side rendering --- nuxt.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/nuxt.config.ts b/nuxt.config.ts index cafe2e0..55bb13d 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -3,6 +3,7 @@ export default defineNuxtConfig({ compatibilityDate: '2024-11-01', devtools: { enabled: true }, modules: ['@nuxt/eslint', '@nuxt/image', "@pinia/nuxt", "@nuxt/icon"], + ssr: false, app: { /* Defines what prefix the client runs on -- 2.47.2 From 22ca450651c9ac82e594e487f1a8b6960a927535 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 28 May 2025 02:17:54 +0200 Subject: [PATCH 02/35] feat: make Loading component a spinning load circle --- components/Loading.vue | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/components/Loading.vue b/components/Loading.vue index 14a379d..c9b38ac 100644 --- a/components/Loading.vue +++ b/components/Loading.vue @@ -1,6 +1,6 @@ @@ -8,6 +8,31 @@ - \ No newline at end of file -- 2.47.2 From 6a11108ec15a7eba5af10c2570797c0b10b6c080 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 28 May 2025 02:18:29 +0200 Subject: [PATCH 03/35] feat: add auth middleware --- middleware/auth.global.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 middleware/auth.global.ts diff --git a/middleware/auth.global.ts b/middleware/auth.global.ts new file mode 100644 index 0000000..e567c70 --- /dev/null +++ b/middleware/auth.global.ts @@ -0,0 +1,17 @@ +export default defineNuxtRouteMiddleware(async (to, from) => { + console.log("to.path:", to.path); + const accessToken = useCookie("access_token").value; + if (["/login", "/register"].includes(to.path)) { + if (accessToken) { + return await navigateTo("/"); + } + return; + }; + + if (!accessToken) { + const { refresh } = useAuth(); + console.log("hi"); + await refresh(); + return await navigateTo("/login"); + } +}) -- 2.47.2 From a15f85a08276b3824890a1c7fbd7ede015180761 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 28 May 2025 02:24:54 +0200 Subject: [PATCH 04/35] fix: refresh returning 401 not properly logging you out of client --- composables/auth.ts | 20 +++---- utils/fetchWithApi.ts | 129 +++++++++++++++++++++++------------------- 2 files changed, 79 insertions(+), 70 deletions(-) diff --git a/composables/auth.ts b/composables/auth.ts index ccb45ca..7ce077c 100644 --- a/composables/auth.ts +++ b/composables/auth.ts @@ -30,11 +30,11 @@ export const useAuth = () => { { username, password: hashedPass, device_name: "Linux Laptop" } - }) as { access_token: string, refresh_token: string }; fetch + }) as { access_token: string, refresh_token: string }; console.log("hi"); accessToken.value = res.access_token; console.log("access token:", accessToken.value); - await fetchUser(); + //await fetchUser(); } async function logout(password: string) { @@ -60,19 +60,17 @@ export const useAuth = () => { async function refresh() { console.log("refreshing"); - try { - const res = await fetchWithApi("/auth/refresh", { - method: "POST" - }) as { access_token: string }; - accessToken.value = res.access_token; - console.log("set new access token"); - } catch (error) { - console.error("refresh error:", error); - } + const res = await fetchWithApi("/auth/refresh", { + method: "POST" + }) as any; + console.log("finished refreshing:", res); + accessToken.value = res?.access_token; + console.log("set new access token"); } async function fetchUser() { if (!accessToken.value) return; + console.log("fetchuser access token:", accessToken.value); const res = await fetchWithApi("/users/me") as UserResponse; user.value = res; return user.value; diff --git a/utils/fetchWithApi.ts b/utils/fetchWithApi.ts index c0ebf2e..11856fb 100644 --- a/utils/fetchWithApi.ts +++ b/utils/fetchWithApi.ts @@ -9,63 +9,74 @@ export default async (path: string, options: NitroFetchOptions = {}) path = path.slice(0, path.lastIndexOf("/")); } console.log("formatted path:", path); - try { - const accessToken = useCookie("access_token"); - console.log("access token:", accessToken.value); - const apiBase = useCookie("api_base").value; - const apiVersion = useRuntimeConfig().public.apiVersion; - console.log("heyoooo") - console.log("apiBase:", apiBase); - if (!apiBase) { - console.log("no api base"); - return; - } - console.log("path:", path) - const { revoke, refresh } = useAuth(); - console.log("access token 2:", accessToken.value); - - let headers: HeadersInit = {}; - - if (accessToken.value) { - headers = { - ...options.headers, - "Authorization": `Bearer ${accessToken.value}` - }; - } else { - headers = { - ...options.headers - }; - } - - let reauthFailed = false; - while (!reauthFailed) { - try { - console.log("fetching:", URL.parse(apiBase + path)); - const res = await $fetch(URL.parse(apiBase + path)!.href, { - ...options, - headers, - credentials: "include" - }); - - return res; - } catch (error: any) { - if (error?.response?.status === 401) { - if (!path.startsWith("/auth/refresh")) { - try { - await refresh(); - } catch (error: any) { - if (error?.response?.status === 401) { - reauthFailed = true; - await revoke(); - return; - } - } - } - } - throw error; - } - } - } catch (error) { - console.error("error:", error); - } + const accessToken = useCookie("access_token"); + console.log("access token:", accessToken.value); + const apiBase = useCookie("api_base").value; + const apiVersion = useRuntimeConfig().public.apiVersion; + console.log("heyoooo") + console.log("apiBase:", apiBase); + if (!apiBase) { + console.log("no api base"); + return; + } + console.log("path:", path) + const { revoke, refresh } = useAuth(); + console.log("access token 2:", accessToken.value); + + let headers: HeadersInit = {}; + + if (accessToken.value) { + headers = { + ...options.headers, + "Authorization": `Bearer ${accessToken.value}` + }; + } else { + headers = { + ...options.headers + }; + } + + let reauthFailed = false; + while (!reauthFailed) { + try { + console.log("fetching:", URL.parse(apiBase + path)); + const res = await $fetch(URL.parse(apiBase + path)!.href, { + ...options, + headers, + credentials: "include" + }); + + return res; + } catch (error: any) { + console.error("Error fetching resource"); + if (error?.response?.status === 401) { + console.log("Error status is 401"); + if (!path.startsWith("/auth/refresh")) { + console.log("Path is not refresh endpoint"); + try { + console.log("Trying to refresh"); + await refresh(); + console.log("Successfully refreshed token"); + } catch (error: any) { + console.log("Failed to refresh token"); + if (error?.response?.status === 401) { + console.log("Refresh returned 401"); + reauthFailed = true; + console.log("Revoking"); + await revoke(); + console.log("Redirecting to login"); + await navigateTo("/login"); + console.log("redirected"); + return; + } + } + } else { + console.log("Path is refresh endpoint, throwing error"); + throw error; + } + } + console.log("throwing error"); + throw error; + } + } } -- 2.47.2 From 9f6490d744e8879ee6fd79d74d1c5f990967295e Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 28 May 2025 02:26:17 +0200 Subject: [PATCH 05/35] feat: add verify-email page, wip --- pages/verify-email.vue | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 pages/verify-email.vue diff --git a/pages/verify-email.vue b/pages/verify-email.vue new file mode 100644 index 0000000..cae02ea --- /dev/null +++ b/pages/verify-email.vue @@ -0,0 +1,32 @@ + + + + + \ No newline at end of file -- 2.47.2 From 8bfa17631c32d0e41a25b064082695bacaa1b511 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 28 May 2025 02:27:22 +0200 Subject: [PATCH 06/35] feat: add support for redirect_to query param in register page --- pages/register.vue | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pages/register.vue b/pages/register.vue index cd17005..18276ee 100644 --- a/pages/register.vue +++ b/pages/register.vue @@ -33,7 +33,7 @@
- Already have an account? Log in! + Already have an account? Log in!
@@ -74,7 +74,9 @@ const errorMessages = reactive({ //const authStore = useAuthStore(); const auth = useAuth(); -const redirectTo = useRoute().query.redirect_to; +const query = useRoute().query as Record; +const searchParams = new URLSearchParams(query); +const loginUrl = `/login?${searchParams}` onMounted(() => { if (auth.accessToken.value) { @@ -120,7 +122,12 @@ const apiVersion = useRuntimeConfig().public.apiVersion; async function register(e: Event) { e.preventDefault(); console.log("Sending registration data"); - await auth.register(form.username, form.email, form.password); + try { + await auth.register(form.username, form.email, form.password); + return await navigateTo(query.redirect_to); + } catch (error) { + console.error("Error registering:", error); + } //return navigateTo(redirectTo ? redirectTo as string : useAppConfig().baseURL as string); } -- 2.47.2 From e1cce87cdb6b87638c389a5895f87d36816077ef Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 28 May 2025 02:28:09 +0200 Subject: [PATCH 07/35] fix: always redirecting to / due to missing if statement in login page --- pages/login.vue | 68 +++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/pages/login.vue b/pages/login.vue index 485166d..4ae6de3 100644 --- a/pages/login.vue +++ b/pages/login.vue @@ -1,46 +1,60 @@ -- 2.47.2 From 073e93cb572ce7935dd1f3407db077c16f066997 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 28 May 2025 02:29:05 +0200 Subject: [PATCH 08/35] feat: move Loading in auth layout to outside root container --- layouts/auth.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/layouts/auth.vue b/layouts/auth.vue index f90dc84..f9d5bff 100644 --- a/layouts/auth.vue +++ b/layouts/auth.vue @@ -1,7 +1,7 @@