0Pricing
Next.js 15 Fullstack Web Apps · Lesson

Role-Based Access Control (RBAC)

Model user roles and permissions, store them in the session, and enforce role checks across server components, route handlers, and middleware in a Next.js 15 app.

Role-Based Access Control (RBAC) is a free Next.js 15 Fullstack Web Apps lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Next.js 15 Fullstack Web Apps learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Authorization Beyond Login

Authentication answers who are you; authorization answers what may you do. Role-Based Access Control (RBAC) assigns each user one or more roles and grants permissions to roles instead of individuals.

  • Roles: admin, editor, viewer
  • Permissions are derived from the role.

Storing the Role in the JWT

With NextAuth, attach the role to the token in the jwt callback so it travels with every request without a database hit.

callbacks: {
  async jwt({ token, user }) {
    if (user) token.role = user.role;
    return token;
  },
  async session({ session, token }) {
    session.user.role = token.role;
    return session;
  },
}

A Permissions Map

Centralize what each role can do. A simple map keeps checks consistent and easy to audit.

export const permissions = {
  admin: ['read', 'write', 'delete'],
  editor: ['read', 'write'],
  viewer: ['read'],
};

export function can(role, action) {
  return permissions[role]?.includes(action) ?? false;
}

Testing the Helper

The can helper is pure logic, so it runs anywhere. Here is a self-contained check.

const permissions = {
  admin: ['read', 'write', 'delete'],
  editor: ['read', 'write'],
  viewer: ['read'],
};
function can(role, action) {
  return permissions[role]?.includes(action) ?? false;
}
console.log(can('editor', 'write'));
console.log(can('viewer', 'delete'));

Guarding a Server Component

Read the session on the server and redirect users who lack the required role before any sensitive UI renders.

import { auth } from '@/auth';
import { redirect } from 'next/navigation';

export default async function AdminPage() {
  const session = await auth();
  if (session?.user.role !== 'admin') redirect('/');
  return <h1>Admin Dashboard</h1>;
}

Guarding a Route Handler

API route handlers must enforce roles too. Never trust the client. Return 403 when the role is insufficient.

import { auth } from '@/auth';
import { can } from '@/lib/rbac';

export async function DELETE(req) {
  const session = await auth();
  if (!can(session?.user.role, 'delete')) {
    return new Response('Forbidden', { status: 403 });
  }
  return Response.json({ ok: true });
}

Role Checks in Middleware

Middleware can block whole route groups early. Match an admin prefix and verify the token's role.

import { NextResponse } from 'next/server';

export function middleware(req) {
  const role = req.cookies.get('role')?.value;
  if (req.nextUrl.pathname.startsWith('/admin') && role !== 'admin') {
    return NextResponse.redirect(new URL('/login', req.url));
  }
  return NextResponse.next();
}

export const config = { matcher: ['/admin/:path*'] };

Defense in Depth

Apply checks at multiple layers. Middleware gives a fast first gate, but always re-verify in the server component or route handler that actually touches data.

  • Middleware: coarse routing gate.
  • Server component / handler: authoritative check.

Hiding UI Conditionally

Hide controls users cannot use, but remember UI hiding is convenience, not security. The server must still reject unauthorized actions.

export default async function Toolbar() {
  const session = await auth();
  return (
    <div>
      {can(session?.user.role, 'delete') && <DeleteButton />}
    </div>
  );
}

Multiple Roles and Scopes

Real apps often give a user several roles or fine-grained scopes. Store an array and check membership. This scales toward permission-based (ABAC) systems later.

function hasRole(userRoles, required) {
  return userRoles.some((r) => r === required);
}
console.log(hasRole(['editor', 'viewer'], 'editor'));

Common Pitfalls

Avoid these RBAC mistakes:

  • Trusting a role sent from the client body.
  • Checking roles only in the UI.
  • Forgetting to re-issue the JWT after a role change.
  • Hardcoding role strings instead of a central map.

Quick Check

Where is the authoritative place to enforce that only admins can delete a record?

Recap

You implemented RBAC end to end:

  • Stored the role in the JWT and session via NextAuth callbacks.
  • Centralized permissions with a can() helper.
  • Guarded server components, route handlers, and middleware.
  • Applied defense in depth and avoided client-trust pitfalls.

Frequently asked questions

Is the “Role-Based Access Control (RBAC)” lesson free?

Yes — the full text of “Role-Based Access Control (RBAC)” is free to read here on the web, and the Next.js 15 Fullstack Web Apps course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Next.js 15 Fullstack Web Apps course, upgrade to CoddyKit PRO.

What will I learn in “Role-Based Access Control (RBAC)”?

Model user roles and permissions, store them in the session, and enforce role checks across server components, route handlers, and middleware in a Next.js 15 app. You practise Next.js 15 Fullstack Web Apps with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Next.js 15 Fullstack Web Apps?

No prior experience is required. Next.js 15 Fullstack Web Apps on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Role-Based Access Control (RBAC)” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Next.js 15 Fullstack Web Apps lesson?

Yes. Every Next.js 15 Fullstack Web Apps lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Integrating NextAuth.js
  2. Session Management and JWTs
  3. Middleware and Access Control
  4. Role-Based Access Control (RBAC)
← Back to Next.js 15 Fullstack Web Apps