RegisterLogin
DocsPricing
RegisterLogin
  • Getting Started
  • Introduction
  • Quick Start
  • SDKs
  • React
  • TypeScript
  • Next.js
  • Express
  • NestJS
  • Python
  • API Reference
  • Support and Resources
  • FAQ
  • Contact Support

AuthSafe

Product

HighlightFeatureIntegrationPricingFAQ

Company

AboutBlogContactSitemap

Developer

DashboardDocumentation

Legal

Terms & ConditionsPrivacyComplianceShippingCancellation

© 2026 AuthSafe. All rights reserved.

We value your privacy

This website uses cookies for anonymous analytics to help us improve your experience. No personal information is stored or shared. You can allow or reject analytics tracking at any time. See our Privacy Policy.

We use cookies for anonymous analytics. No personal info is stored. See our Privacy Policy.

Middleware

Next.js middleware for protecting routes and route groups with automatic authentication checks.

Overview

AuthSafe provides two middleware functions for route protection:
  1. createAuthMiddleware() - Full route protection with redirects
  2. authMiddleware() - Simple authentication check without enforcement
Edge Runtime Compatible
Both middleware functions work with Next.js Edge Runtime for optimal performance.

createAuthMiddleware()

Create middleware that protects specific routes and redirects unauthenticated users to sign in.
function createAuthMiddleware(config: MiddlewareConfig): Middleware;

Configuration

interface MiddlewareConfig {
  authConfig: AuthSafeConfig;
  protectedRoutes?: (string | RegExp)[];
  publicRoutes?: (string | RegExp)[];
  signInUrl?: string;
  beforeRedirect?: (req: NextRequest) => void | Promise<void>;
}

Parameters

  • authConfig - AuthSafe configuration (clientId, domain, etc.)
  • protectedRoutes - Routes requiring authentication
  • publicRoutes - Routes accessible without auth (takes precedence)
  • signInUrl - Where to redirect unauthenticated users (default: /api/auth/signin)
  • beforeRedirect - Callback before redirecting (e.g., logging)

Basic Usage

// middleware.ts
import { createAuthMiddleware } from 'authsafe-nextjs/server';

export default createAuthMiddleware({
  authConfig: {
    clientId: process.env.NEXT_PUBLIC_AUTHSAFE_CLIENT_ID!,
    domain: process.env.NEXT_PUBLIC_AUTHSAFE_DOMAIN!,
  },
  protectedRoutes: ['/dashboard', '/profile', '/settings'],
  publicRoutes: ['/', '/about', '/pricing'],
  signInUrl: '/api/auth/signin',
});

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

Advanced Examples

Regex Route Patterns

// middleware.ts
import { createAuthMiddleware } from 'authsafe-nextjs/server';

export default createAuthMiddleware({
  authConfig: {
    clientId: process.env.NEXT_PUBLIC_AUTHSAFE_CLIENT_ID!,
    domain: process.env.NEXT_PUBLIC_AUTHSAFE_DOMAIN!,
  },
  protectedRoutes: [
    '/dashboard',
    /^\/admin/, // All /admin/* routes
    /^\/api\/protected/, // Protected API routes
  ],
  publicRoutes: [
    '/',
    '/about',
    /^\/blog/, // All /blog/* routes
  ],
});

export const config = {
  matcher: ['/((?!api/auth|_next/static|_next/image|favicon.ico).*)'],
};

With Before Redirect Hook

// middleware.ts
import { createAuthMiddleware } from 'authsafe-nextjs/server';

export default createAuthMiddleware({
  authConfig: {
    clientId: process.env.NEXT_PUBLIC_AUTHSAFE_CLIENT_ID!,
    domain: process.env.NEXT_PUBLIC_AUTHSAFE_DOMAIN!,
  },
  protectedRoutes: ['/dashboard', /^\/admin/],
  publicRoutes: ['/'],
  signInUrl: '/api/auth/signin',
  beforeRedirect: async (req) => {
    // Log unauthorized access attempt
    console.log(`Unauthorized access attempt: ${req.nextUrl.pathname}`);

    // Send analytics event
    await fetch('https://analytics.example.com/track', {
      method: 'POST',
      body: JSON.stringify({ path: req.nextUrl.pathname }),
    });
  },
});

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

Protect All Routes Except Public

// middleware.ts
import { createAuthMiddleware } from 'authsafe-nextjs/server';

export default createAuthMiddleware({
  authConfig: {
    clientId: process.env.NEXT_PUBLIC_AUTHSAFE_CLIENT_ID!,
    domain: process.env.NEXT_PUBLIC_AUTHSAFE_DOMAIN!,
  },
  protectedRoutes: ['/'], // Protect everything
  publicRoutes: ['/', '/about', '/pricing', '/blog', /^\/blog\//],
});

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

authMiddleware()

Simple middleware that adds authentication status to requests without enforcing it.
function authMiddleware(authConfig: AuthSafeConfig): Middleware;

Usage

// middleware.ts
import { authMiddleware } from 'authsafe-nextjs/server';

export default authMiddleware({
  clientId: process.env.NEXT_PUBLIC_AUTHSAFE_CLIENT_ID!,
  domain: process.env.NEXT_PUBLIC_AUTHSAFE_DOMAIN!,
});

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

Accessing Auth Status

The middleware adds a custom header you can check:
// app/api/route.ts
import { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  const isAuthenticated =
    request.headers.get('x-authsafe-authenticated') === '1';

  if (!isAuthenticated) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 });
  }

  return Response.json({ data: 'Protected data' });
}

Route Matching

String Patterns

protectedRoutes: [
  '/dashboard', // Exact match or any sub-path
  '/profile', // /profile, /profile/edit, etc.
  '/settings',
];

Regex Patterns

protectedRoutes: [
  /^\/admin/, // All /admin/* routes
  /^\/api\/user/, // All /api/user/* routes
  /\/private$/, // Any route ending with /private
];

Precedence

Public routes take precedence over protected routes:
{
  protectedRoutes: ['/'],           // Protect everything
  publicRoutes: ['/', '/about'],    // Except these
}

Matcher Config

Always configure the matcher to exclude static assets and API routes:
export const config = {
  matcher: [
    /*
     * Match all request paths except:
     * - api (API routes)
     * - _next/static (static files)
     * - _next/image (image optimization)
     * - favicon.ico (favicon file)
     */
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

Exclude Auth Routes

export const config = {
  matcher: ['/((?!api/auth|_next/static|_next/image|favicon.ico).*)'],
};

Complete Examples

Multi-Tenant App

// middleware.ts
import { createAuthMiddleware } from 'authsafe-nextjs/server';

export default createAuthMiddleware({
  authConfig: {
    clientId: process.env.NEXT_PUBLIC_AUTHSAFE_CLIENT_ID!,
    domain: process.env.NEXT_PUBLIC_AUTHSAFE_DOMAIN!,
  },
  protectedRoutes: [
    /^\/dashboard/,
    /^\/workspace/,
    /^\/settings/,
    /^\/org\/.+\/admin/, // Organization admin pages
  ],
  publicRoutes: ['/', '/pricing', '/features', /^\/blog/, /^\/docs/],
  signInUrl: '/signin',
  beforeRedirect: async (req) => {
    console.log(`[Auth] Redirecting ${req.nextUrl.pathname} to signin`);
  },
});

export const config = {
  matcher: ['/((?!api/auth|_next|favicon.ico|public).*)'],
};

SaaS Application

// middleware.ts
import { createAuthMiddleware } from 'authsafe-nextjs/server';

export default createAuthMiddleware({
  authConfig: {
    clientId: process.env.NEXT_PUBLIC_AUTHSAFE_CLIENT_ID!,
    domain: process.env.NEXT_PUBLIC_AUTHSAFE_DOMAIN!,
  },
  protectedRoutes: [
    '/app', // Main app
    '/billing', // Billing pages
    '/team', // Team management
    '/integrations', // Integrations
  ],
  publicRoutes: ['/', '/pricing', '/about', '/contact', /^\/blog/, /^\/help/],
  signInUrl: '/login',
});

export const config = {
  matcher: [
    '/((?!api/auth|_next/static|_next/image|favicon.ico|.*\\.(?:jpg|jpeg|png|gif|svg|webp)).*)',
  ],
};

Best Practices

  1. Always exclude static assets from matcher to avoid unnecessary processing
  2. Use regex for pattern matching when protecting route groups
  3. List public routes explicitly to avoid accidental exposure
  4. Log unauthorized attempts using beforeRedirect for security monitoring
  5. Keep middleware lightweight to maintain fast response times

Troubleshooting

Middleware Not Running

Make sure your matcher config is correct:
export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

Infinite Redirect Loop

Ensure your sign in URL is not protected:
{
  protectedRoutes: ['/dashboard'],
  signInUrl: '/api/auth/signin',  // ✅ Not protected
}
Or explicitly mark it as public:
{
  protectedRoutes: ['/'],
  publicRoutes: ['/api/auth/signin'],  // ✅ Explicitly public
  signInUrl: '/api/auth/signin',
}

Related

  • Server Authentication - getAuth(), requireAuth()
  • API Handlers - Sign in/out endpoints
  • useAuth() - Client-side authentication