Skip to main content
Protect routes and require authentication before allowing access to specific pages in your application.

Implementation

import { useMoonKey } from '@moon-key/react-auth';
import { ReactNode } from 'react';
import { Navigate } from 'react-router-dom';

interface ProtectedRouteProps {
  children: ReactNode;
}

export function ProtectedRoute({ children }: ProtectedRouteProps) {
  const { isAuthenticated, ready } = useMoonKey();

  // Wait for MoonKey to initialize
  if (!ready) {
    return (
      <div className="loading-screen">
        <div className="spinner" />
        <p>Loading...</p>
      </div>
    );
  }

  // Redirect to login if not authenticated
  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }

  // Render protected content
  return <>{children}</>;
}

// Usage in your router:
// <Route path="/dashboard" element={
//   <ProtectedRoute>
//     <Dashboard />
//   </ProtectedRoute>
// } />

Usage examples

React Router v6

import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { ProtectedRoute } from './ProtectedRoute';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/login" element={<LoginPage />} />
        <Route path="/signup" element={<SignupPage />} />
        
        {/* Protected routes */}
        <Route
          path="/dashboard"
          element={
            <ProtectedRoute>
              <Dashboard />
            </ProtectedRoute>
          }
        />
        
        <Route
          path="/profile"
          element={
            <ProtectedRoute>
              <ProfilePage />
            </ProtectedRoute>
          }
        />
        
        <Route
          path="/settings"
          element={
            <ProtectedRoute>
              <SettingsPage />
            </ProtectedRoute>
          }
        />
      </Routes>
    </BrowserRouter>
  );
}

Next.js App Router

'use client';

import { useMoonKey } from '@moon-key/react-auth';
import { useRouter } from 'next/navigation';
import { useEffect, ReactNode } from 'react';

export function ProtectedRoute({ children }: { children: ReactNode }) {
  const { isAuthenticated, ready } = useMoonKey();
  const router = useRouter();

  useEffect(() => {
    if (ready && !isAuthenticated) {
      router.push('/login');
    }
  }, [ready, isAuthenticated, router]);

  if (!ready) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return null; // Will redirect in useEffect
  }

  return <>{children}</>;
}

// Usage in app/dashboard/page.tsx:
// export default function DashboardPage() {
//   return (
//     <ProtectedRoute>
//       <Dashboard />
//     </ProtectedRoute>
//   );
// }

Advanced patterns

With redirect to original destination

import { Navigate, useLocation } from 'react-router-dom';

export function ProtectedRoute({ children }: { children: ReactNode }) {
  const { isAuthenticated, ready } = useMoonKey();
  const location = useLocation();

  if (!ready) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    // Redirect to login, but save the current location
    return <Navigate to="/login" state={{ from: location }} replace />;
  }

  return <>{children}</>;
}

// In your login component, redirect back after login:
// const location = useLocation();
// const from = location.state?.from?.pathname || '/dashboard';
// navigate(from, { replace: true });

With role-based access

interface ProtectedRouteProps {
  children: ReactNode;
  requiredRole?: string;
}

export function ProtectedRoute({ children, requiredRole }: ProtectedRouteProps) {
  const { user, isAuthenticated, ready } = useMoonKey();

  if (!ready) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }

  if (requiredRole && user?.role !== requiredRole) {
    return <Navigate to="/unauthorized" replace />;
  }

  return <>{children}</>;
}

// Usage:
// <Route path="/admin" element={
//   <ProtectedRoute requiredRole="admin">
//     <AdminPanel />
//   </ProtectedRoute>
// } />

With wallet requirement

export function WalletProtectedRoute({ children }: { children: ReactNode }) {
  const { user, isAuthenticated, ready } = useMoonKey();

  if (!ready) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }

  if (!user?.wallet) {
    return <Navigate to="/create-wallet" replace />;
  }

  return <>{children}</>;
}

Key concepts

  • Authentication check - Verifies user is logged in
  • Loading state - Shows loading while SDK initializes
  • Automatic redirect - Sends unauthenticated users to login
  • Preserve location - Can remember where user tried to go
  • Flexible protection - Can add additional requirements (roles, wallets, etc.)

Important notes

Always check the ready state before checking isAuthenticated to avoid redirecting users while MoonKey is still initializing.
Use replace prop in Navigate to prevent users from going back to protected routes using the browser back button.

Next steps