Nextbase Docs
Nextbase Docs
HomeBlogWelcome to Nextbase v3!Getting Started with NextBaseQuick setup
Admin Panel GuideAsynchronous Data Fetching GuideAuthenticationCreating Admin Panel PageCreating Docs PageCreating in-app notificationsCreating a new Supabase tableCreating a Protected PageCreating Public Dynamic PageCreating Public Static PageHandling Realtime Data With SupabaseManaging UsersMutating Data With SupabaseOptimizing Data Operations in Next.js 14 and SupabaseRemoving InternationalizationRow Level SecurityStripe Setup in Nextbase UltimateWriting Integration Tests with PlaywrightWriting Unit Tests with Vitest
Guides

Creating a Protected Page

A complete guide on creating and managing protected routes in Nextbase using a two-tier protection system, including correct middleware configuration and an example scenario.

Nextbase implements a two-tier protection system for routes that require authentication:

  1. Middleware Protection: Fast, preliminary check
  2. Layout-based Protection: Thorough, database-validated check

Middleware Protection

The middleware provides a quick, preliminary check based on the presence of an authentication cookie. This happens before the page rendering begins, offering a performance-optimized way to redirect unauthenticated users.

// Simplified middleware.ts
import { NextRequest, NextResponse } from "next/server";
import { createSupabaseMiddlewareClient } from "./supabase-clients/user/createSupabaseMiddlewareClient";

const protectedPaths = ["/dashboard", "/settings", "/profile" /* ... */];

const middlewares = [
  {
    matcher: protectedPaths.map((path) =>
      urlJoin("/", `(${LOCALE_GLOB_PATTERN})`, path),
    ),
    middleware: async (req) => {
      const supabase = createSupabaseMiddlewareClient(req);
      const {
        data: { session },
      } = await supabase.auth.getSession();
      if (!session) {
        return NextResponse.redirect(new URL("/login", req.url));
      }
      return NextResponse.next();
    },
  },
  // Other middleware configurations...
];

export async function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;
  for (const { matcher, middleware } of middlewares) {
    if (matchesPath(matcher, pathname)) {
      return await middleware(request);
    }
  }
  return NextResponse.next();
}

This middleware quickly checks for the presence of a session, providing a fast redirect to the login page if no session is found. This enhances website performance by avoiding unnecessary page renders for unauthenticated users.

Layout-based Protection

The layout protection provides a more thorough check, validating the session against the database to ensure it's still valid and not stale.

// src/app/(dynamic-pages)/(authenticated-pages)/layout.tsx
import { ReactNode } from "react";
import { redirect } from "next/navigation";
import { createSupabaseUserServerComponentClient } from "@/supabase-clients/user/createSupabaseUserServerComponentClient";

export default async function Layout({ children }: { children: ReactNode }) {
  const supabase = createSupabaseUserServerComponentClient();
  const { data, error } = await supabase.auth.getUser();

  if (error || !data.user) {
    return redirect("/login");
  }

  // Additional checks can be performed here, e.g., user roles, permissions, etc.

  return <>{children}</>;
}

This layout-based check provides a more comprehensive validation, ensuring that even if a user has a cookie, it corresponds to a valid, active session in the database. This prevents access with stale or invalid sessions.

Example: Creating a New Protected Route "/my-protected-page"

Let's walk through the correct process of creating a new protected route "/my-protected-page" in Nextbase, leveraging the two-tier protection system.

Step 1: Create the Page File

Create a new file at the following path:

src/app/(dynamic-pages)/(authenticated-pages)/my-protected-page/page.tsx

Add your page content to this file:

export default function MyProtectedPage() {
  return (
    <div>
      <h1>My Protected Page</h1>
      <p>This is a protected page only accessible to authenticated users.</p>
    </div>
  );
}

Step 2: Update Middleware Configuration

You need to manually add the new route to the protectedPaths array in the middleware configuration. Open the middleware.ts file and update it as follows:

// In middleware.ts
const protectedPaths = [
  // ... existing protected paths ...
  `/my-protected-page(/.*)?`,
];

const middlewares = [
  {
    matcher: protectedPaths.map((path) =>
      urlJoin("/", `(${LOCALE_GLOB_PATTERN})`, path),
    ),
    middleware: async (req) => {
      // Existing middleware logic
    },
  },
  // If you need custom logic for this specific route, you can add it here:
  {
    matcher: ["/my-protected-page"],
    middleware: async (req) => {
      // Custom logic for /my-protected-page if needed
      // For example, checking for specific user roles
      const supabase = createSupabaseMiddlewareClient(req);
      const {
        data: { session },
      } = await supabase.auth.getSession();
      if (!session) {
        return NextResponse.redirect(new URL("/login", req.url));
      }
      // Additional checks can be performed here
      return NextResponse.next();
    },
  },
];

By manually adding the new route to the protectedPaths array, you ensure that it's covered by the middleware protection, providing the fast, preliminary check.

Step 3: Layout-based Protection (Automatic)

Your new page is automatically protected by the authenticated layout, as it's placed under the (authenticated-pages) directory:

src/app/(dynamic-pages)/(authenticated-pages)/layout.tsx

This layout performs the thorough, database-validated check for all pages within this directory, ensuring that even if a user passes the middleware check, their session is still valid and active.

Step 4: Add Navigation (Optional)

If you want to add navigation to your new protected page, update your navigation component:

// In your navigation component
<Link href="/my-protected-page">My Protected Page</Link>

Testing Your New Protected Route

To test your new protected route and verify the two-tier protection:

  1. Start your Nextbase application
  2. Try accessing "/my-protected-page" without logging in
    • You should be quickly redirected to the login page by the middleware
  3. Log in with a valid user account
  4. Access "/my-protected-page"
    • The middleware will allow access (fast check)
    • The layout protection will perform a thorough check
    • You should see your protected page content
  5. Invalidate your session (e.g., by logging out in another tab)
  6. Try accessing "/my-protected-page" again
    • The middleware might initially allow access (if the cookie is still present)
    • The layout protection should detect the invalid session and redirect to login

By following these steps and understanding the two-tier protection system, you've successfully created a new protected route in your Nextbase application. This route is secured by both fast middleware checks and thorough layout-based validation, ensuring optimal performance and robust security for your application.

Creating a new Supabase table

Learn how to create a new table in Supabase, manage migrations, and use the new table in your Next.js app.

Creating Public Dynamic Page

Guide on how to create a public dynamic page in a Next.js application such as in Nextbase.

On this page

Middleware ProtectionLayout-based ProtectionExample: Creating a New Protected Route "/my-protected-page"Step 1: Create the Page FileStep 2: Update Middleware ConfigurationStep 3: Layout-based Protection (Automatic)Step 4: Add Navigation (Optional)Testing Your New Protected Route