Authorization in Next.js – Optimistic Checks, Data Access Layer, and Role-Based Control

Once a user is authenticated, authorization in Next.js determines what routes and data they can access. This article explains optimistic and secure checks, using Proxy for early redirects, building a centralized Data Access Layer (DAL), applying Data Transfer Objects (DTOs), and rendering components based on user roles in Server Components.

~3 min read • Updated Oct 26, 2025

Introduction


Authorization in Next.js ensures that authenticated users only access what they’re allowed to. There are two main types of checks:

  • Optimistic: Uses session data from cookies for fast UI decisions and redirects.
  • Secure: Uses session data from the database for sensitive operations.

Optimistic Checks with Proxy


Use proxy.ts to redirect users based on session data:

// proxy.ts
import { NextRequest, NextResponse } from 'next/server'
import { decrypt } from '@/app/lib/session'
import { cookies } from 'next/headers'

const protectedRoutes = ['/dashboard']
const publicRoutes = ['/login', '/signup', '/']

export default async function proxy(req: NextRequest) {
  const path = req.nextUrl.pathname
  const isProtected = protectedRoutes.includes(path)
  const isPublic = publicRoutes.includes(path)

  const cookie = (await cookies()).get('session')?.value
  const session = await decrypt(cookie)

  if (isProtected && !session?.userId) {
    return NextResponse.redirect(new URL('/login', req.nextUrl))
  }

  if (isPublic && session?.userId && !path.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/dashboard', req.nextUrl))
  }

  return NextResponse.next()
}

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

Creating a Data Access Layer (DAL)


Centralize your auth logic with a DAL. Start with verifySession():

// app/lib/dal.ts
import { cookies } from 'next/headers'
import { decrypt } from '@/app/lib/session'

export const verifySession = cache(async () => {
  const cookie = (await cookies()).get('session')?.value
  const session = await decrypt(cookie)

  if (!session?.userId) {
    redirect('/login')
  }

  return { isAuth: true, userId: session.userId }
})

Use it in data requests:

export const getUser = cache(async () => {
  const session = await verifySession()
  if (!session) return null

  const data = await db.query.users.findMany({
    where: eq(users.id, session.userId),
    columns: { id: true, name: true, email: true },
  })

  return data[0]
})

Using DTOs to Secure Data


Return only the necessary fields to the client:

// app/lib/dto.ts
import { getUser } from '@/app/lib/dal'

function canSeeUsername(viewer) {
  return true
}

function canSeePhoneNumber(viewer, team) {
  return viewer.isAdmin || team === viewer.team
}

export async function getProfileDTO(slug) {
  const data = await db.query.users.findMany({ where: eq(users.slug, slug) })
  const user = data[0]
  const currentUser = await getUser(user.id)

  return {
    username: canSeeUsername(currentUser) ? user.username : null,
    phonenumber: canSeePhoneNumber(currentUser, user.team)
      ? user.phonenumber
      : null,
  }
}

Role-Based Rendering in Server Components


Use verifySession() to conditionally render based on user role:

// app/dashboard/page.tsx
import { verifySession } from '@/app/lib/dal'

export default async function Dashboard() {
  const session = await verifySession()
  const userRole = session?.user?.role

  if (userRole === 'admin') {
    return <AdminDashboard />
  } else if (userRole === 'user') {
    return <UserDashboard />
  } else {
    redirect('/login')
  }
}

Auth Checks in Layouts


Due to partial rendering, avoid doing auth checks directly in layouts. Instead, fetch user data and rely on DAL to enforce authorization:

// app/layout.tsx
export default async function Layout({ children }) {
  const user = await getUser()
  return (
    // ...
  )
}

Conclusion


Authorization in Next.js combines fast optimistic checks with secure database validation. By using Proxy, DAL, DTOs, and role-based rendering, you can build scalable and secure access control across your application.


Written & researched by Dr. Shahin Siami