aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-10-05 17:14:59 +0000
committerMohamedBassem <me@mbassem.com>2024-10-05 17:15:36 +0000
commitf1c956a361539592d00836488181b69218798600 (patch)
treeff975397e3ecb4063675962857441623082c2175
parent3a8d197437868ca10d294f0174afa013f138ec33 (diff)
downloadkarakeep-f1c956a361539592d00836488181b69218798600.tar.zst
feature(web): Async validate JWT account and sign out the user if they no longer exist
-rw-r--r--apps/web/app/dashboard/layout.tsx2
-rw-r--r--apps/web/components/utils/ValidAccountCheck.tsx26
-rw-r--r--packages/trpc/routers/users.ts13
3 files changed, 39 insertions, 2 deletions
diff --git a/apps/web/app/dashboard/layout.tsx b/apps/web/app/dashboard/layout.tsx
index 23c379cb..b0ac1f7d 100644
--- a/apps/web/app/dashboard/layout.tsx
+++ b/apps/web/app/dashboard/layout.tsx
@@ -2,6 +2,7 @@ import MobileSidebar from "@/components/dashboard/sidebar/ModileSidebar";
import Sidebar from "@/components/dashboard/sidebar/Sidebar";
import DemoModeBanner from "@/components/DemoModeBanner";
import { Separator } from "@/components/ui/separator";
+import ValidAccountCheck from "@/components/utils/ValidAccountCheck";
import serverConfig from "@hoarder/shared/config";
@@ -14,6 +15,7 @@ export default async function Dashboard({
}>) {
return (
<div className="flex min-h-screen w-screen flex-col sm:h-screen sm:flex-row">
+ <ValidAccountCheck />
<div className="hidden flex-none sm:flex">
<Sidebar />
</div>
diff --git a/apps/web/components/utils/ValidAccountCheck.tsx b/apps/web/components/utils/ValidAccountCheck.tsx
new file mode 100644
index 00000000..12c11087
--- /dev/null
+++ b/apps/web/components/utils/ValidAccountCheck.tsx
@@ -0,0 +1,26 @@
+"use client";
+
+import { api } from "@/lib/trpc";
+import { signOut } from "next-auth/react";
+
+/**
+ * This component is used to address a confusion when the JWT token exists but the user no longer exists in the database.
+ * So this component synchronusly checks if the user is still valid and if not, signs out the user.
+ */
+export default function ValidAccountCheck() {
+ const { error } = api.users.whoami.useQuery(undefined, {
+ retry: (_failureCount, error) => {
+ if (error.data?.code === "UNAUTHORIZED") {
+ return false;
+ }
+ return true;
+ },
+ });
+ if (error?.data?.code === "UNAUTHORIZED") {
+ signOut({
+ callbackUrl: "/",
+ });
+ }
+
+ return <></>;
+}
diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts
index 51f9429e..ba1aee24 100644
--- a/packages/trpc/routers/users.ts
+++ b/packages/trpc/routers/users.ts
@@ -1,5 +1,5 @@
import { TRPCError } from "@trpc/server";
-import { count, eq } from "drizzle-orm";
+import { and, count, eq } from "drizzle-orm";
import invariant from "tiny-invariant";
import { z } from "zod";
@@ -138,7 +138,16 @@ export const usersAppRouter = router({
email: z.string().nullish(),
}),
)
- .query(({ ctx }) => {
+ .query(async ({ ctx }) => {
+ if (!ctx.user.email) {
+ throw new TRPCError({ code: "UNAUTHORIZED" });
+ }
+ const userDb = await ctx.db.query.users.findFirst({
+ where: and(eq(users.id, ctx.user.id), eq(users.email, ctx.user.email)),
+ });
+ if (!userDb) {
+ throw new TRPCError({ code: "UNAUTHORIZED" });
+ }
return { id: ctx.user.id, name: ctx.user.name, email: ctx.user.email };
}),
});