Indie Kit DocsIndie Kit Docs
Tutorials

Creating Protected Pages

Learn how to create authenticated pages and routes in Indie Kit using server-side, client-side, and API authentication

Creating Protected Pages 🔒

Indie Kit provides multiple ways to protect your pages and routes based on authentication. Let's explore how to create protected content using different approaches! 🛡️

🔐 Protected by Default

In Indie Kit, these routes are automatically protected:

  • Any page in src/app/(in-app)/app/*
  • Any API route in src/app/api/app/*

No additional authentication code is needed for these paths!

Server-Side Protected Pages 🔐

For server components and pages, use the auth helper from @/auth. Here's an example of a protected dashboard page:

// src/app/dashboard/page.tsx
import { auth } from '@/auth'
import { forbidden } from 'next/navigation'
 
export default async function DashboardPage() {
  const session = await auth()
  
  if (!session) {
    // User is not authenticated, return 403 Forbidden
    forbidden()
  }
 
  return (
    <div className="p-8">
      <h1 className="text-2xl font-bold">
        Welcome back, {session.user.name}! 👋
      </h1>
      <div className="mt-4">
        {/* Your protected dashboard content */}
      </div>
    </div>
  )
}

⚙️ Required Configuration

To use forbidden() from Next.js, you must enable it in your next.config.js:

import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  experimental: {
    authInterrupts: true,
  },
}
 
export default nextConfig

Client-Side Protected Pages 💻

For client components, use the useUser hook from @/lib/users. This hook provides user data and loading states:

// src/app/profile/page.tsx
'use client'
 
import useUser from '@/lib/users/useUser'
import { redirect } from 'next/navigation'
 
export default function ProfilePage() {
  const { user, isLoading } = useUser()
 
  // Show loading state while checking authentication
  if (isLoading) {
    return <div>Loading... ⌛</div>
  }
 
  // Redirect if not authenticated
  if (!user) {
    redirect('/login')
  }
 
  return (
    <div className="p-8">
      <h1 className="text-2xl font-bold">
        Your Profile ✨
      </h1>
      <div className="mt-4">
        <p>Email: {user.email}</p>
        <p>Name: {user.name}</p>
        {/* More profile content */}
      </div>
    </div>
  )
}

Protected API Routes 🔌

For API routes, use the withAuthRequired middleware to ensure authentication:

// src/app/api/user-data/route.ts
import withAuthRequired from '@/lib/auth/withAuthRequired'
import { NextResponse } from 'next/server'
 
export const GET = withAuthRequired(async (req, context) => {
  const { session } = context
 
  // Your protected API logic here
  const userData = {
    name: session.user.name,
    email: session.user.email,
    // ... other user data
  }
 
  return NextResponse.json(userData)
})

Best Practices 🌟

  1. 🔒 Always validate authentication on both client and server side
  2. ⚡️ Use loading states to improve user experience
  3. 🚦 Implement proper redirects for unauthenticated users
  4. 🛡️ Combine with role-based access control when needed
  5. 🔐 Keep sensitive data in protected routes
  6. 📝 Add clear error messages for unauthorized access

Authentication Flow Tips 💡

  • Server-side authentication is more secure for initial page loads
  • Client-side checks are great for dynamic content and better UX
  • API routes should always use withAuthRequired for protection
  • Consider implementing refresh token logic for longer sessions
  • Use loading states to prevent flash of unauthorized content

Now you can create secure, authenticated pages in your Indie Kit app! Remember to always validate user permissions before displaying sensitive content. 🚀

On this page