From 27c4a4a6e0111effdf7311a37faeec403b63720a Mon Sep 17 00:00:00 2001 From: teetyff Date: Wed, 27 May 2026 05:51:35 +0100 Subject: [PATCH] Add authentication files: AuthGuard, middleware, and useAuth hook --- AuthGuard.tsx | 33 +++++++++++++++++++++++++++++++++ middleware.ts | 32 ++++++++++++++++++++++++++++++++ useAuth.ts | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 AuthGuard.tsx create mode 100644 middleware.ts create mode 100644 useAuth.ts diff --git a/AuthGuard.tsx b/AuthGuard.tsx new file mode 100644 index 00000000..50d5d1ff --- /dev/null +++ b/AuthGuard.tsx @@ -0,0 +1,33 @@ +'use client'; + +import { useEffect } from 'react'; +import { useRouter, usePathname } from 'next/navigation'; +import { useAuth } from '@/hooks/useAuth'; +import { Loader2 } from 'lucide-react'; + +export function AuthGuard({ children }: { children: React.ReactNode }) { + const { isAuthenticated, isLoading } = useAuth(); + const router = useRouter(); + const pathname = usePathname(); + + useEffect(() => { + if (!isLoading && !isAuthenticated) { + // Fallback client-side redirect + router.push(`/?callbackUrl=${encodeURIComponent(pathname)}`); + } + }, [isLoading, isAuthenticated, router, pathname]); + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (!isAuthenticated) { + return null; + } + + return <>{children}; +} \ No newline at end of file diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 00000000..5cfd3bc8 --- /dev/null +++ b/middleware.ts @@ -0,0 +1,32 @@ +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +// Define paths that require authentication +const PROTECTED_ROUTES = ['/dashboard', '/portfolio', '/settings', '/invest']; + +export function middleware(request: NextRequest) { + const { pathname } = request.nextUrl; + + // Check if the current path is a protected route + const isProtectedRoute = PROTECTED_ROUTES.some(route => pathname.startsWith(route)); + + if (isProtectedRoute) { + // Look for the auth token in cookies + // This assumes your auth flow sets a cookie named 'auth-token' + const token = request.cookies.get('auth-token')?.value; + + if (!token) { + // Redirect to home or login page if no token is found + const loginUrl = new URL('/', request.url); + // Optionally add a redirect parameter to return the user after login + loginUrl.searchParams.set('callbackUrl', pathname); + return NextResponse.redirect(loginUrl); + } + } + + return NextResponse.next(); +} + +export const config = { + matcher: ['/dashboard/:path*', '/portfolio/:path*', '/settings/:path*', '/invest/:path*'], +}; \ No newline at end of file diff --git a/useAuth.ts b/useAuth.ts new file mode 100644 index 00000000..b174950f --- /dev/null +++ b/useAuth.ts @@ -0,0 +1,47 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { useWalletConnector } from './useWalletConnector'; + +interface AuthState { + isAuthenticated: boolean; + isLoading: boolean; + userAddress: string | null; +} + +export function useAuth() { + const { connectWallet } = useWalletConnector(); + const [authState, setAuthState] = useState({ + isAuthenticated: false, + isLoading: true, + userAddress: null, + }); + + useEffect(() => { + // Check for existing session/token on mount + const checkAuth = async () => { + try { + // In a real Web3 app, we'd check if the wallet is still connected + // and if a valid session token exists in cookies + const hasToken = document.cookie.includes('auth-token='); + + // Mocking check - in production, validate JWT or wallet state here + setAuthState({ + isAuthenticated: hasToken, + isLoading: false, + userAddress: hasToken ? '0x...' : null, // Get from wallet provider + }); + } catch (error) { + setAuthState({ + isAuthenticated: false, + isLoading: false, + userAddress: null, + }); + } + }; + + checkAuth(); + }, []); + + return authState; +} \ No newline at end of file