Next.js
I. Next.js Fundamentals
1. Introduction to Next.js
2. Next.js vs React
3. Project Setup
4. Folder Structure
5. Pages and Routing
6. Link and Navigation
7. Static Assets
8. CSS and Styling
II. Routing, Data & Rendering
9. Dynamic Routing
10. API Routes
11. Data Fetching Basics
12. getStaticProps
13. getServerSideProps
14. Incremental Static Regeneration
15. Rendering Strategies
16. Image Optimization
III. Advanced Next.js & Performance
17. Middleware
18. Authentication Basics
19. Authorization
20. Environment Variables
21. Performance Optimization
22. SEO with Next.js
23. Internationalization
24. Error Handling
IV. Projects, Deployment & Best Practices
25. Next.js Best Practices
26. Folder and Code Organization
27. Testing Next.js Apps
28. Security in Next.js
29. Next.js Interview Questions
30. Mini Project – Blog
31. Mini Project – Dashboard
32. Mini Project – Ecommerce
33. Mini Project – API Integration
34. Next.js Case Study
35. Real-World Use Cases
36. Project Planning
37. Final Project
38. Deployment with Vercel
39. Course Review
40. Career Roadmap
Lesson 19
Authorization
Build role-based access control and permission systems to secure different areas of NewsWave based on user roles and permissions.
Authorization controls what authenticated users can do. While authentication answers "Who are you?", authorization answers "What can you do?". The NewsWave editorial team needs different permission levels — editors can publish articles, writers can draft them, and subscribers can only read premium content.
Authorization happens after authentication. You know who the user is, now you decide what they can access. GitHub uses this pattern perfectly — you can view public repos (no auth needed), contribute to repos you have access to (authorization), or create private repos (paid authorization).
Modern web apps use role-based access control (RBAC). Users get roles like "admin", "editor", or "user". Each role has specific permissions. The system checks these permissions before showing content or processing requests.
Understanding Authorization vs Authentication
Authentication and authorization work together but solve different problems. Authentication verifies identity — like showing your driver's license at a bar. Authorization checks permissions — like the bouncer deciding if you can enter the VIP section based on your membership level. Many developers confuse these concepts. You can be authenticated but not authorized. Think about Vercel's dashboard — you can log in (authenticated) but only see projects you own or have been invited to (authorized). The system knows who you are, but limits what you can do. Authorization happens at multiple layers. Frontend authorization hides UI elements users shouldn't see. Backend authorization protects API routes and database operations. Both layers are essential — never rely on frontend-only authorization for security.// Frontend authorization - hide UI elements
function ArticleActions({ user, article }) {
// Only show edit button if user can edit this article
const canEdit = user.role === 'editor' || user.id === article.authorId;
return (
<div>
{canEdit && <EditButton />}
<ShareButton />
</div>
);
}localhost:3000 — NewsWave
What just happened?
The component checks user permissions before rendering the edit button. Editors see edit buttons on all articles, while writers only see them on articles they authored. The share button appears for everyone since sharing is a universal permission.
Role-Based Access Control (RBAC)
RBAC organizes permissions around roles instead of individual users. You assign roles to users, and roles contain specific permissions. This scales better than managing permissions per user — imagine GitHub giving repository access to each developer individually instead of using team roles. Roles form a hierarchy in most systems. An "admin" role might include all "editor" permissions, plus additional admin-only features. This inheritance reduces complexity and makes permission management predictable. The NewsWave team needs different roles for their editorial workflow. Subscribers read content, writers create drafts, editors publish articles, and admins manage the entire system. Each role builds upon the previous one's permissions.// Define roles and their permissions for NewsWave
const ROLES = {
subscriber: {
name: 'Subscriber',
permissions: ['read:articles', 'read:comments'] // Basic reading access
},
writer: {
name: 'Writer',
permissions: ['read:articles', 'create:drafts', 'edit:own_drafts'] // Can write
},
editor: {
name: 'Editor',
permissions: ['read:articles', 'create:articles', 'edit:all_articles', 'publish:articles'] // Can publish
}
};Terminal
$ mkdir lib/auth && touch lib/auth/permissions.js
Creating authorization utilities...
✓ Permission system files created
// Check if user has specific permission
function hasPermission(user, permission) {
// Get user's role from the ROLES object
const role = ROLES[user.role];
if (!role) return false; // Role doesn't exist
// Check if role includes this permission
return role.permissions.includes(permission);
}localhost:3000 — NewsWave
What just happened?
The permission system checks each user's role against required permissions. Subscribers can only read, writers can also create drafts, and editors have full publishing rights. The visual checkmarks show exactly what each role can access.
Protecting API Routes
API route protection happens on the server where users can't manipulate it. Frontend authorization improves user experience, but backend authorization provides real security. Attackers can bypass frontend checks, but they can't fake server-side authentication tokens. Next.js API routes check authorization before processing requests. Extract the user's session, verify their role, then decide whether to continue or return an error. This pattern protects every backend operation. The NewsWave publishing system needs secure API endpoints. Only editors should publish articles, only writers should create drafts, and only admins should delete content. Each endpoint validates permissions before executing.// API route with role-based authorization
import { getServerSession } from 'next-auth/next';
import { authOptions } from '../auth/[...nextauth]';
export default async function handler(req, res) {
// Get user session from the request
const session = await getServerSession(req, res, authOptions);
if (!session) {
return res.status(401).json({ error: 'Not authenticated' }); // Must be logged in
}
}Terminal
$ mkdir pages/api/articles && touch pages/api/articles/publish.js
Creating protected API endpoint...
✓ Publish endpoint ready for authorization
// Complete API route with permission checking
export default async function publishArticle(req, res) {
const session = await getServerSession(req, res, authOptions);
if (!session) {
return res.status(401).json({ error: 'Authentication required' });
}
// Check if user has publish permission
if (!hasPermission(session.user, 'publish:articles')) {
return res.status(403).json({ error: 'Insufficient permissions' }); // Forbidden
}
// User is authenticated and authorized - process the request
const { articleId } = req.body;
// Publish the article logic here...
res.status(200).json({ success: true, message: 'Article published' });
}Terminal
$ curl -X POST localhost:3000/api/articles/publish -d '{"articleId":123}'
{"error":"Authentication required"}
$ curl -X POST localhost:3000/api/articles/publish -H "Authorization: Bearer token" -d '{"articleId":123}'
{"success":true,"message":"Article published"}
What just happened?
The API endpoint validates authentication first, then checks specific permissions. Unauthenticated requests get 401 errors, unauthorized requests get 403 errors, and valid requests proceed normally. This creates multiple security layers.
Middleware Authorization
Next.js middleware runs before pages load, making it perfect for route-level authorization. Instead of checking permissions in every page component, middleware handles access control centrally. This prevents unauthorized users from even seeing protected pages. Middleware executes at the edge — closer to users than your main server. This means faster authorization decisions and better user experience. Vercel's edge network runs your middleware code globally. The NewsWave admin panel needs middleware protection. Editors shouldn't see admin-only pages, and regular users shouldn't access the content management system at all. Middleware redirects unauthorized users before pages render.// middleware.js - runs before every request
import { withAuth } from 'next-auth/middleware';
export default withAuth(
function middleware(req) {
// This runs after authentication is verified
const { pathname } = req.nextUrl;
const userRole = req.nextauth.token?.role;
// Protect admin routes - only admins allowed
if (pathname.startsWith('/admin') && userRole !== 'admin') {
return Response.redirect(new URL('/unauthorized', req.url)); // Redirect away
}
}
);Terminal
$ touch middleware.js
Creating middleware file...
✓ Middleware will protect routes automatically
// Configure which routes middleware should protect
export const config = {
matcher: [
'/admin/:path*', // All admin routes
'/editor/:path*', // All editor routes
'/api/articles/:path*' // All article API routes
]
};
// Alternative: protect everything except public routes
export const config = {
matcher: ['/((?!api/auth|_next/static|favicon.ico).*)']
};localhost:3000 — NewsWave
What just happened?
Middleware configuration determines which routes need protection. Public routes like article pages remain open, while editor and admin routes require specific roles. The matcher patterns use wildcards to protect entire route sections efficiently.
Resource-Level Authorization
Resource-level authorization controls access to specific items, not just pages or features. A writer might have permission to edit articles, but only articles they created. This granular control prevents users from modifying other people's content. GitHub demonstrates this perfectly — you can edit files in repositories you own or have write access to, but not in other people's private repos. The system checks both your general permissions and your relationship to each specific resource. NewsWave needs resource-level controls for article management. Writers should edit their own drafts but not published articles by other authors. Editors can modify any article, but regular subscribers can't edit anything.// Check if user can access specific resource
function canAccessResource(user, resource, action) {
// Check general permission first
if (!hasPermission(user, `${action}:articles`)) {
return false; // User doesn't have base permission
}
// Check ownership for certain actions
if (action === 'edit' && user.role === 'writer') {
return user.id === resource.authorId; // Writers can only edit own articles
}
return true; // Editors and admins can access any resource
}Terminal
$ touch lib/auth/resource-permissions.js
Creating resource-level authorization...
✓ Resource access control ready
// Database query with authorization built in
async function getArticlesForUser(user) {
if (user.role === 'editor' || user.role === 'admin') {
// Editors see all articles
return await db.articles.findMany();
}
if (user.role === 'writer') {
// Writers only see their own articles
return await db.articles.findMany({
where: { authorId: user.id } // Filter by ownership
});
}
// Subscribers see only published articles
return await db.articles.findMany({
where: { status: 'published' } // Filter by publication status
});
}localhost:3000 — NewsWave
What just happened?
Each user sees different articles based on their role and ownership. Editors see everything, writers only see their own content, and subscribers see only published articles. The authorization happens at the data level, not just in the UI.
Authorization Context and Hooks
React Context provides authorization data throughout your component tree without prop drilling. Create an authorization context that combines user data with permission checking functions. Components can then access authorization state anywhere in the app. Custom hooks wrap authorization logic in reusable functions. Instead of duplicating permission checks across components, create hooks likeusePermission or useCanEdit. This centralizes authorization logic and makes components cleaner.
The NewsWave frontend needs consistent authorization throughout the interface. Navigation menus, article lists, and action buttons all need to check user permissions. Context and hooks provide this seamlessly.
// Authorization context for the entire app
import { createContext, useContext } from 'react';
const AuthContext = createContext();
export function AuthProvider({ children, user }) {
// Permission checking function available everywhere
const hasPermission = (permission) => {
const role = ROLES[user?.role];
return role?.permissions.includes(permission) || false;
};
return (
<AuthContext.Provider value={{ user, hasPermission }}>
{children}
</AuthContext.Provider>
);
}Terminal
$ mkdir context && touch context/AuthContext.js
Setting up authorization context...
✓ Global authorization state ready
// Custom hooks for common authorization patterns
export function useAuth() {
const context = useContext(AuthContext);
if (!context) throw new Error('useAuth must be used within AuthProvider');
return context; // Returns user and hasPermission
}
export function usePermission(permission) {
const { hasPermission } = useAuth();
return hasPermission(permission); // Returns true/false
}
export function useCanEdit(resource) {
const { user } = useAuth();
return canAccessResource(user, resource, 'edit'); // Returns true/false
}localhost:3000 — NewsWave
What just happened?
The authorization context provides permission checking throughout the app. Custom hooks make it easy for components to check specific permissions. Writers only see basic actions, while editors get additional publish and edit buttons. Switch between roles to see the difference.
Security Best Practices
Never rely on frontend authorization alone — it can be bypassed. Always validate permissions on the server. Use HTTPS for all authentication tokens. Implement rate limiting on sensitive endpoints. Log authorization failures for security monitoring. Store minimal user data in frontend sessions.
Quiz
1. Why is backend authorization more secure than frontend authorization in NewsWave?
2. What should a NewsWave API route do after verifying user authentication?
3. How does Next.js middleware help protect NewsWave's admin routes?
Up Next: Environment Variables
Secure your NewsWave app configuration with environment variables for API keys, database URLs, and deployment settings across development and production environments.