Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions AuthGuard.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="flex h-screen w-full items-center justify-center">
<Loader2 className="h-8 w-8 animate-spin text-primary" />
</div>
);
}

if (!isAuthenticated) {
return null;
}

return <>{children}</>;
}
32 changes: 32 additions & 0 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -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*'],
};
47 changes: 47 additions & 0 deletions useAuth.ts
Original file line number Diff line number Diff line change
@@ -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<AuthState>({
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;
}