Next.js - Authorization



What is Authorization?

Authorization is the process of determining whether a user is allowed to access a particular resource such as a page, route or an API endpoint in a web application. Once the user is logged in, the authorization logic will determine what actions the user is allowed to perform.

Types of Authorization

There are two types of authorization checks:

  • Optimistic: In this type of authorization, the check is done using the session data stored in the cookie. These checks are useful for quick operations, such as showing/hiding UI elements or redirecting users based on permissions or roles.
  • Secure: In this type of authorization, the check is done using a token stored in the database. These checks are useful for more complex operations, such as authorizing API endpoints or authorizing user actions.

To implement both types of these authorization checks, follow the steps below:

  • Create a Data Access Layer to centralize your authorization logic
  • Use Data Transfer Objects (DTO) to only return the necessary data to the client
  • Use Middleware to perform optimistic checks. (optional)

Create a Data Access Layer

Data Access Layer is a layer that is responsible for performing all the database operations. It is used to centralize all the authorization logic.

The Data Access Layer should include a function that verifies the user's session as they interact with the application. At the very least, the function should check if the session is valid, then redirect or return the user information needed to make further requests.

Example

In the code below, we have created a Data Access Layer that verifies the user's session. The function returns the user information if the session is valid, otherwise it redirects the user to the login page.

// app/lib/auth.ts

import 'server-only'
 
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 Data Transfer Objects

Data Transfer Objects (DTO) is a pattern that is used to transfer data between the client and server. It is used to only return the necessary data to the client. This is useful when you want to reduce the amount of data that is sent to the client.

In the code below, we have created a DTO that contains the user information. This DTO is used to return the user information to the client.

// app/lib/definitions.ts

export type User = {
    id: number
    name: string
    email: string
}
Advertisements