🛡️ withSupaAuth()

Protect your routes and auto-refresh sessions effortlessly in your Next.js Middleware.

Instead of copying 40-50 lines of cookie chunking and refresh logic directly from Supabase's documentation for every new Next.js project, withSupaAuth condenses everything into one functional macro.

Basic Usage

To configure authentication middleware, call withSupaAuth inside middleware.ts and set your preferred matched routes:

// middleware.ts
import { withSupaAuth } from "next-supa-utils/server";

export default withSupaAuth({
  routes: [{ path: "/admin/:path*" }, { path: "/dashboard" }],
  redirectTo: "/login",
});

// Configure the Matcher to run on all paths except static assets
export const config = { matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"] };

API Reference

Returns: (request: NextRequest) => Promise<NextResponse>

Configuration Options:

PropertyTypeRequiredDefaultDescription
routesRouteConfig[]Definitions for your routes
redirectTostring"/login"Global fallback route if an unauthenticated user hits a protected match
publicRoutesstring[][]Routes that are always public, escaping any wildcard prefix match
onAuthSuccessFunctionOptional callback fired after successful verification
roleExtractorFunctionCustom function to parse user roles
supabaseUrlstringprocess.envOverride explicit Supabase URL
supabaseAnonKeystringprocess.envOverride explicit Supabase Anon Key

RouteConfig Options

The routes array accepts objects matching the RouteConfig interface for granular Role-Based Access Control (RBAC):

interface RouteConfig {
  path: string; // The route prefix to match, e.g "/admin" or wildcards "/admin/:path*"
  allowedRoles?: string[]; // Array of acceptable roles (e.g. ["admin", "editor"])
}

[!important] When allowedRoles is omitted, the middleware simply checks if a valid session exists. If the user is logged in, they are immediately granted access.

Handling Unauthorized Access

If an unauthenticated user requests a protected route, they are automatically redirected. withSupaAuth appends their original destination as a next query parameter (e.g., /login?next=/admin/dashboard). You can read this param on the client to smoothly bounce them back after logging in!