Skip to content

Middleware Documentation ​

Overview ​

This section documents all route middleware used in the Collage Brand Portal application. Middleware provides route protection, authentication checks, URL validation, and automatic redirects. Middleware files are located in app/middleware/ and run before page components are rendered.

Middleware Architecture ​

Middleware in Nuxt 4 follows a hierarchical execution model where middleware runs before page components, allowing for route protection, validation, and redirects.

Architecture Pattern ​

┌─────────────────────────────────────────┐
│      Route Navigation Request            │  ← User navigates to route
├─────────────────────────────────────────┤
│      Global Middleware                   │  ← Runs on ALL routes
│      (auth.global.ts)                    │
├─────────────────────────────────────────┤
│      Per-Route Middleware                │  ← Runs on specific routes
│      (auth.ts, check-url.ts, etc.)       │
├─────────────────────────────────────────┤
│      Page Component                      │  ← Renders if middleware allows
└─────────────────────────────────────────┘

Execution Flow ​

  1. Global Middleware (*.global.ts) - Runs first on every navigation
  2. Per-Route Middleware - Runs if specified in definePageMeta
  3. Page Component - Renders if all middleware passes

Middleware Structure ​

app/middleware/
├── auth.global.ts                    # Global authentication middleware (runs on all routes)
├── auth.ts                           # Per-route authentication middleware
├── check-url.ts                      # URL validation and brand verification middleware
├── redirect-if-logged-in.ts          # Redirect authenticated users from auth pages
├── public-portal-home.ts             # Public portal auto-login on home page
├── public-portal-login-redirect.ts   # Public portal auto-login on login page
└── public-portal-search.ts           # Public portal search page handling

Total: 7 middleware files

Middleware Types ​

Global Middleware ​

Files with .global.ts suffix run automatically on every page navigation. They cannot be disabled and run before any per-route middleware.

Example: auth.global.ts - Runs on all routes to check authentication

Per-Route Middleware ​

Files without .global.ts suffix run only when explicitly specified in page metadata. They provide optional, page-specific logic.

Usage:

vue
<script setup lang="ts">
definePageMeta({
  middleware: 'auth'  // Runs auth.ts middleware
})
</script>

Middleware Components ​

Global Authentication Middleware ​

File: auth.global.ts

Runs on ALL pages automatically. Handles:

  • Authentication state validation
  • User data fetching if token exists
  • Protected route enforcement
  • Public route exclusion

Key Features:

  • Server-side and client-side execution
  • Automatic user data hydration
  • Public route detection
  • Token-based route support

Per-Route Authentication Middleware ​

File: auth.ts

Optional authentication check for specific pages. Provides additional authentication validation when needed.

Usage:

vue
definePageMeta({
  middleware: 'auth'
})

URL Validation Middleware ​

File: check-url.ts

Comprehensive URL and brand validation middleware. Handles:

  • Brand name validation
  • Reserved slug detection
  • Domain verification
  • Brand switching logic
  • Anonymous user handling
  • Public portal detection

Key Features:

  • Brand existence verification
  • Domain-based routing
  • Session management
  • Cookie hydration
  • Error handling

Redirect If Logged In Middleware ​

File: redirect-if-logged-in.ts

Prevents authenticated users from accessing authentication pages. Redirects to dashboard if user is already logged in.

Protected Pages:

  • Login
  • Forgot password
  • Reset password
  • Generate password

Public Portal Home Middleware ​

File: public-portal-home.ts

Handles public portal auto-login on brand home page. Client-only middleware that checks if workspace is a public portal and auto-logs in.

Key Features:

  • Client-only execution
  • Public portal detection
  • Automatic login
  • Session validation

Public Portal Login Redirect Middleware ​

File: public-portal-login-redirect.ts

Auto-logs in public portals when accessing login page. Skips login page for public portals to avoid redirect flash.

Key Features:

  • Client-only execution
  • Public portal detection
  • Automatic redirect to home
  • Login page bypass

Public Portal Search Middleware ​

File: public-portal-search.ts

Guard for unauthenticated visitors on /:brand_name/search. If the workspace is a public portal, auto-login so search results can load; otherwise redirect to login with redirect query preserved.

Key Features:

  • Client-only execution
  • Public portal detection via usePublicPortal
  • Session check before redirect
  • Redirect to login with return URL

Middleware Execution Order ​

1. Global Middleware (auth.global.ts) ​

  • Runs first on every page navigation
  • Handles authentication state
  • Fetches user data if needed
  • Enforces protected routes

2. Per-Route Middleware ​

  • Runs after global middleware
  • Executes in order specified in definePageMeta
  • Can override or extend global behavior

3. Page Component ​

  • Renders after all middleware passes
  • Receives validated route and state

Middleware Patterns ​

Basic Middleware Structure ​

typescript
export default defineNuxtRouteMiddleware(async (to, from) => {
  // Middleware logic
  
  // Redirect example
  return navigateTo('/login')
  
  // Allow navigation (no return or return undefined)
})

Authentication Check Pattern ​

typescript
export default defineNuxtRouteMiddleware(async (to) => {
  const authStore = useAuthStore()
  
  if (!authStore.isAuthenticated) {
    return navigateTo('/login')
  }
})

Conditional Redirect Pattern ​

typescript
export default defineNuxtRouteMiddleware(async (to, from) => {
  const authStore = useAuthStore()
  
  if (authStore.isAuthenticated && to.path.includes('/login')) {
    return navigateTo('/dashboard')
  }
})

Public Route Detection Pattern ​

typescript
export default defineNuxtRouteMiddleware(async (to) => {
  const isPublicRoute = to.path.startsWith('/shared-assets') || 
                       to.path.includes('/login')
  
  if (isPublicRoute) {
    return // Allow access
  }
  
  // Protected route logic
})

Async Operations Pattern ​

typescript
export default defineNuxtRouteMiddleware(async (to) => {
  try {
    const result = await someAsyncOperation()
    
    if (!result) {
      return navigateTo('/error')
    }
  } catch (error) {
    console.error('Middleware error:', error)
    return navigateTo('/error')
  }
})

Public Routes ​

Routes that don't require authentication:

  • /shared-assets/* - Public shared assets
  • */login - Login page
  • */forgot-password - Password recovery
  • */reset-password - Password reset
  • */generate-password - Password generation
  • */[token] - Token-based routes

Protected Routes ​

All other routes require authentication. The global auth middleware automatically:

  • Checks authentication state
  • Redirects unauthenticated users to login
  • Fetches user data if token exists

Middleware Best Practices ​

  1. Global vs Per-Route: Use global middleware for app-wide logic (authentication, analytics)
  2. Performance: Keep middleware lightweight and fast - avoid heavy computations
  3. Error Handling: Handle errors gracefully with try/catch
  4. Redirects: Use navigateTo() for redirects, return the result
  5. Async Operations: Use async/await for async operations
  6. Store Access: Access stores directly in middleware (they're available)
  7. SSR Compatibility: Ensure middleware works in both SSR and client contexts
  8. Avoid Side Effects: Keep middleware focused on navigation logic
  9. Public Route Detection: Always check for public routes before enforcing auth
  10. Client-Only Logic: Use import.meta.client or import.meta.server checks when needed

Common Use Cases ​

Route Protection ​

typescript
// Protect route if not authenticated
if (!authStore.isAuthenticated) {
  return navigateTo(`/${brandName}/login`)
}

Conditional Access ​

typescript
// Allow access based on condition
if (user.role !== 'admin') {
  return navigateTo('/unauthorized')
}

URL Validation ​

typescript
// Validate URL structure
if (!isValidBrand(brandName)) {
  throw createError({
    statusCode: 404,
    statusMessage: 'Brand not found'
  })
}

Session Management ​

typescript
// Hydrate session from cookies
if (import.meta.server) {
  const token = useCookie('auth_token')
  if (token.value) {
    authStore.initialize(token.value)
  }
}