diff --git a/app/api/auth/session/route.ts b/app/api/auth/session/route.ts new file mode 100644 index 0000000..8e00fd8 --- /dev/null +++ b/app/api/auth/session/route.ts @@ -0,0 +1,17 @@ +import { NextRequest, NextResponse } from "next/server"; + +/** + * GET /api/auth/session + * Verify the user's session. + * The middleware already checks the JWT and auth_sessions database. + * If this handler is reached, the session is valid. + */ +export async function GET(req: NextRequest) { + return NextResponse.json( + { + valid: true, + message: "Session is valid", + }, + { status: 200 } + ); +} diff --git a/components/WalletConnect.tsx b/components/WalletConnect.tsx index 07e4f24..fac8a19 100644 --- a/components/WalletConnect.tsx +++ b/components/WalletConnect.tsx @@ -3,6 +3,7 @@ import { createContext, useContext, useMemo, useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Wallet } from "lucide-react"; +import { toast } from "sonner"; import { Dialog, DialogContent, @@ -28,18 +29,42 @@ export function WalletProvider({ children }: { children: React.ReactNode }) { const [error, setError] = useState(null); const [token, setToken] = useState(null); - // Load token from localStorage on mount + // Load and verify token from localStorage on mount useEffect(() => { - const storedToken = localStorage.getItem("authToken"); - const storedPublicKey = localStorage.getItem("walletAddress"); - const storedWalletName = localStorage.getItem("walletName"); - - if (storedToken && storedPublicKey) { - setToken(storedToken); - setPublicKey(storedPublicKey); - setWalletName(storedWalletName); - setConnected(true); - } + const initSession = async () => { + const storedToken = localStorage.getItem("authToken"); + const storedPublicKey = localStorage.getItem("walletAddress"); + const storedWalletName = localStorage.getItem("walletName"); + + if (storedToken && storedPublicKey) { + setConnecting(true); + try { + const res = await fetch("/api/auth/session", { + headers: { Authorization: `Bearer ${storedToken}` }, + }); + + if (res.ok) { + setToken(storedToken); + setPublicKey(storedPublicKey); + setWalletName(storedWalletName); + setConnected(true); + } else { + // Session expired or invalid + localStorage.removeItem("authToken"); + localStorage.removeItem("walletAddress"); + localStorage.removeItem("walletName"); + setConnected(false); + toast.error("Session expired. Please reconnect your wallet."); + } + } catch (error) { + console.error("Session verification failed:", error); + } finally { + setConnecting(false); + } + } + }; + + initSession(); }, []); const connect = async (walletType: "freighter" | "albedo" | "lobstr") => { diff --git a/middleware.ts b/middleware.ts index 8f17fa1..7f5f23b 100644 --- a/middleware.ts +++ b/middleware.ts @@ -25,6 +25,7 @@ export async function middleware(req: NextRequest) { "/api/snippets", // All snippet operations "/api/profile", // Profile routes "/dashboard", // Dashboard routes + "/api/auth/session", // Session verification ]; // Check if current route is protected