public inbox for [email protected]
 help / color / mirror / Atom feed
From: Muhammad Rizki <[email protected]>
To: Ammar Faizi <[email protected]>
Cc: Muhammad Rizki <[email protected]>,
	Alviro Iskandar Setiawan <[email protected]>,
	GNU/Weeb Mailing List <[email protected]>
Subject: [PATCH v2 12/12] fix(auth): fix auth guard when credentials is invalid
Date: Sun,  9 Mar 2025 02:26:54 +0700	[thread overview]
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>

This commit fixes auth guard to prevent invalid credentials to call API,
it will redirect user to the login page if credentials is invalid.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 src/lib/hooks/auth.svelte.ts          | 26 +++++++++++++++++++++-----
 src/lib/hooks/http.svelte.ts          |  4 +++-
 src/routes/(protected)/+layout.svelte |  9 +++++++++
 src/routes/(protected)/+layout.ts     |  9 ++++++++-
 src/routes/+page.ts                   |  2 ++
 5 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/src/lib/hooks/auth.svelte.ts b/src/lib/hooks/auth.svelte.ts
index 7bd2d3b..aa4beda 100644
--- a/src/lib/hooks/auth.svelte.ts
+++ b/src/lib/hooks/auth.svelte.ts
@@ -5,6 +5,17 @@ let data = $state<LoginResponse>({
   token_exp_at: 0
 });
 
+const getUserFromLocalStorage = () => {
+  const user = localStorage.getItem("gwm_uinfo");
+  if (!user) return undefined;
+
+  try {
+    return JSON.parse(user) as User;
+  } catch {
+    return undefined;
+  }
+};
+
 export function useAuth() {
   return {
     get token() {
@@ -24,8 +35,12 @@ export function useAuth() {
     },
 
     refresh() {
-      const user = localStorage.getItem("gwm_uinfo");
-      data.user_info = JSON.parse(user!) as User;
+      const token = localStorage.getItem("gwm_token");
+      const token_exp_at = Number(localStorage.getItem("gwm_token_exp_at"));
+
+      data.user_info = getUserFromLocalStorage();
+      data.token = token!;
+      data.token_exp_at = token_exp_at;
     },
 
     save({ user_info, token, token_exp_at }: LoginResponse) {
@@ -42,15 +57,16 @@ export function useAuth() {
     },
 
     isValid() {
+      const user = getUserFromLocalStorage();
       const token = localStorage.getItem("gwm_token");
-      const user = localStorage.getItem("gwm_uinfo");
+      const expLs = localStorage.getItem("gwm_token_exp_at");
 
-      if (!token || !user) {
+      if (!token || !user || !expLs) {
         this.clear();
         return false;
       }
 
-      const exp = Number(localStorage.getItem("gwm_token_exp_at"));
+      const exp = Number(expLs);
       const unix = Math.round(new Date().getTime() / 1000);
 
       if (unix >= exp) {
diff --git a/src/lib/hooks/http.svelte.ts b/src/lib/hooks/http.svelte.ts
index d3445d9..f30687d 100644
--- a/src/lib/hooks/http.svelte.ts
+++ b/src/lib/hooks/http.svelte.ts
@@ -1,3 +1,4 @@
+import { goto } from "$app/navigation";
 import { PUBLIC_BASE_URL } from "$env/static/public";
 import * as typing from "$typings";
 import axios from "axios";
@@ -53,10 +54,11 @@ client.interceptors.response.use(
     const response = err.response as AxiosResponse<typing.ResponseAPI<typing.RenewTokenResponse>>;
     const status = response ? response.status : null;
 
-    if (status === 403 && response?.data) {
+    if (status !== 200) {
       localStorage.removeItem("gwm_token");
       localStorage.removeItem("gwm_token_exp_at");
       localStorage.removeItem("gwm_uinfo");
+      goto("/");
     }
 
     return response;
diff --git a/src/routes/(protected)/+layout.svelte b/src/routes/(protected)/+layout.svelte
index e88b3fb..f5998a7 100644
--- a/src/routes/(protected)/+layout.svelte
+++ b/src/routes/(protected)/+layout.svelte
@@ -3,8 +3,17 @@
   import AppSidebar from "$components/customs/app-sidebar.svelte";
   import Header from "$components/customs/header.svelte";
   import Separator from "$components/ui/separator/separator.svelte";
+  import { useAuth } from "$lib/hooks/auth.svelte";
+  import { goto, onNavigate } from "$app/navigation";
 
   let { children } = $props();
+
+  const auth = useAuth();
+
+  onNavigate(() => {
+    if (auth.isValid()) return;
+    goto("/");
+  });
 </script>
 
 <Sidebar.Provider class="light">
diff --git a/src/routes/(protected)/+layout.ts b/src/routes/(protected)/+layout.ts
index 06ff2db..951766f 100644
--- a/src/routes/(protected)/+layout.ts
+++ b/src/routes/(protected)/+layout.ts
@@ -9,13 +9,20 @@ export const load: LayoutLoad = async () => {
 
   if (!auth.isValid()) {
     localStorage.setItem("gwm_invalid_creds", String(1));
+    auth.clear();
     return redirect(307, "/");
   }
 
-  const { data } = await http<{ user_info: typing.User }>({
+  const { status, data } = await http<{ user_info: typing.User }>({
     params: { action: "get_user_info" }
   });
 
+  if (status !== 200) {
+    localStorage.setItem("gwm_invalid_creds", String(1));
+    auth.clear();
+    return redirect(307, "/");
+  }
+
   auth.save({
     token: data.res?.renew_token?.token,
     token_exp_at: data.res?.renew_token?.token_exp_at,
diff --git a/src/routes/+page.ts b/src/routes/+page.ts
index 8cbe162..604e967 100644
--- a/src/routes/+page.ts
+++ b/src/routes/+page.ts
@@ -11,6 +11,8 @@ export const load: PageLoad = async () => {
 
   if (auth.isValid()) return redirect(307, "/home");
 
+  auth.refresh();
+
   const form = await superValidate(zod(loginSchema));
   return { form, isInvalidCreds };
 };
-- 
Muhammad Rizki


  parent reply	other threads:[~2025-03-08 19:27 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-08 19:26 [PATCH v2 00/12] Fix Auth Guard, Move SEO Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 01/12] fix(svelte): use relative false Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 02/12] fix(avatar): change avatarImg state to use from auth.user.photo state Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 03/12] chore(profile): add toUpperCase() on getShortName() Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 04/12] fix(profile): make social fields default to empty string Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 05/12] chore(toaster): change toast message position and use richColors Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 06/12] chore(profile): reset password value on success Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 07/12] fix(profile-avatar): add delete avatar method Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 08/12] chore(profile): add space for password confirmation form Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 09/12] feat(ui): add dropdown-menu and update bits-ui version Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 10/12] chore(sidebar-menu): change sidebar menu look Muhammad Rizki
2025-03-08 19:26 ` [PATCH v2 11/12] chore(seo): move seo from layout to /home page Muhammad Rizki
2025-03-08 19:26 ` Muhammad Rizki [this message]
2025-03-08 19:38 ` [PATCH v2 00/12] Fix Auth Guard, Move SEO Ammar Faizi
2025-03-08 19:51   ` Alviro Iskandar Setiawan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox