Authorization

Authorization is the process of verifying that a user has the necessary permissions to access a resource. Learn how to use the pre-configured authorization components and hooks to protect your client-side and server-side routes.

Protecting Client-Side Routes

I have created an easy to use <Authorization /> component that you can use to protect your client-side routes. The component will check if the user has the necessary permissions to access the route. If the user doesn't have the necessary permissions, a fallback component will be rendered.

By default, authentication is required to access every client route.

Keep in mind that protecting sensitive resources on the client-side only is not secure. Always ensure that server-side routes are also protected.

RBAC (Role-Based Access Control)

In a role-based system, different user roles (like USER and ADMIN) have different levels of access. Users are given access based on their role. For example, admins can do everything, while regular users have limited access.

Usage

Here's an example of how you can implement RBAC with the <Authorization /> component to protect your client-side routes:

import { AccessDenied, Authorization } from "@/components/Misc"

import { UsersContent } from "../../components/UsersContent/UsersContent"

export function UsersPage() {
  return (
    <Authorization
      allowedRoles={["ADMIN"]}
      forbiddenFallback={<AccessDenied />}
    >
      <UsersContent />
    </Authorization>
  )
}
  • The <Authorization /> component will check if the user has the role of ADMIN.
  • If the user has the role of ADMIN, the <UsersContent /> component will be rendered.
  • If the user doesn't have the role of ADMIN, the <AccessDenied /> component will be rendered.

PBAC (Policy-Based Access Control)

While RBAC provides a structured way to manage authorization, there are times when a more detailed approach is needed. PBAC offers greater flexibility, especially in cases where access permissions require fine-tuning based on specific criteria.

For RBAC protection, you can use the RBAC component by passing allowed roles to it. However, for stricter protection, you can employ policy checks.

The advantage of using policies is the ability to define custom logic to verify if the user has the necessary permissions to access a resource. For example, the post:delete policy checks if the user is an admin or the author of the comment before allowing them to delete it.

Usage

Here's an example of how you can use the <Authorization /> component with policies to protect your client-side routes:

policies.ts
export const POLICIES = {
  'post:delete': (user: User, post: Post) => {
    if (user.role === 'ADMIN') {
      return true;
    }

    if (user.role === 'USER' && post.author?.id === user.id) {
      return true;
    }

    return false;
  },
}
PostActions.tsx
import { Authorization } from "@/components/Misc"
import { POLICIES } from "@/lib/policies"

export function PostActions() {
  return (
    <Authorization
      policyCheck={POLICIES['post:delete'](user, post)}
    >
      <DeletePostButton />
    </Authorization>
  )
}

Protecting Server-Side Routes

Protecting server-side routes is crucial to ensure that only authenticated users with the necessary permissions can access sensitive resources.

Usage

To protect your server-side routes, you can use the withAuth higher-order function defined in the packages/auth/src/auth/authMiddleware.ts file. This function will check if the user is authenticated and has the necessary role to access the route.

In your server-side route handler, wrap your route with the withAuth function like this:

route.ts
import { withAuth } from "@package/auth"
import { sendError } from "@package/utils"
import { NextResponse } from "next/server"

export const GET = withAuth(
  ({ req, params, searchParams, user }) => {
    try {
      return NextResponse.json(user, { status: 200 })
    } catch (error) {
      return sendError(error, "Failed to get profile.", 500)
    }
  },
  { requiredRoles: ["ADMIN"] }
)

The above code snippet allows only users with the role of ADMIN to access the route.

Parameters

Req

The request object provided by Next.js. It contains information about the incoming HTTP request, such as headers, query parameters, and the body of the request.

Params

An object containing the route parameters for the current route. For example, if your route is /user/:id, params would be an object like { id: '123' }.

SearchParams

An object containing the search parameters from the request URL. For example, if your request URL is /user?id=123, searchParams would be an object like { id: '123' }.

User

The authenticated user's data.

Options

requiredRoles

An optional array of roles that are allowed to access the route. If you don't pass this option, the route will be accessible to all authenticated users.

Last updated on