Frontegg.ai is now available in Beta Get started
Blog

How to Implement RBAC and ABAC Authorization in Node.js APIs with Frontegg

Modern applications demand flexible and context-aware access control models, especially in domains like logistics, supply chain, and finance. Traditionally, Role-Based Access Control (RBAC) has been the de facto model. However, RBAC alone often falls short when business rules require dynamic attributes such as organizational units, teams, or individual ownership identifiers.

This is where Attribute-Based Access Control (ABAC) complements RBAC, enabling fine-grained, policy-driven authorization decisions.

In this post, we will walk through how we combined RBAC and ABAC using Frontegg’s Node.js SDK and a sample Next.js logistics app, ensuring that:

  • Senior managers can access all consignments within their organization.
  • Managers can access consignments belonging to their team or those they own.
  • Individual Contributors (ICs) can only access consignments they personally own.

We will also demonstrate how the same Frontegg session and token flow integrates seamlessly between our frontend Next.js app and our backend Node.js REST API, using Frontegg’s Node.js SDK for authentication and ABAC-style authorization middleware.

Why RBAC alone isn’t enough

RBAC assigns permissions based on static roles (Admin, Manager, User, etc.). While effective for many applications, it lacks the flexibility to make decisions based on runtime attributes such as:

  • Individual ownership (ownerId)
  • Team membership (teamId)
  • Organization (orgId)

By combining RBAC with ABAC, we empower business-centric access models that reflect real-world logistics and supply chain hierarchies.

The RBAC and ABAC authorization model

Our sample project uses the following hybrid model:

RoleABAC Rule
Senior managerCan view, edit, and delete all consignments in their organization (orgId).
ManagerCan view, edit, and delete consignments for their team (teamId) or where they are owner (ownerId).
Individual contributor (IC)Can only view, edit, and delete consignments they own (ownerId).

The following diagram illustrates our hybrid RBAC + ABAC decision flow:

  • Role-based access is first checked (SeniorManager, Manager, IC).
  • Based on the role, additional attribute-based checks are enforced, such as matching ownerId, teamId, or orgId.
  • Only if the role and all applicable attribute checks pass will the user be granted access to the resource.

Technologies used

How it works

Backend protection and token validation

In the backend (app.ts), we secure all /api routes using Frontegg’s middleware:

app.use('/api',
  withAuthentication(),
  (req, res, next) => {
    if (req.frontegg?.user) {
      req.user = req.frontegg.user;
      req.userId = req.frontegg.user.sub;
      req.userTeamId = req.frontegg.user.metadata?.teamId ?? undefined;
      req.userOrgId = req.frontegg.user.tenantId;
    }
    next();
  },
  consignmentRoutes
);

RBAC + ABAC enforcement in the controller layer

In our controllers, every sensitive operation first authorizes the user based on RBAC and ABAC rules, combining req.user.roles and the consignment.orgId, consignment.teamId, or consignment.ownerId.

function authorizeConsignment(user: any, consignment: IConsignment) {
  if (user.roles.includes('SeniorManager')) {
    return consignment.orgId === user.tenantId;
  } else if (user.roles.includes('Manager')) {
    return consignment.teamId === user.metadata?.teamId || consignment.ownerId === user.sub;
  } else if (user.roles.includes('IC')) {
    return consignment.ownerId === user.sub;
  }
  return false;
}

This centralized RBAC and ABAC enforcement ensures your business rules remain consistent, auditable, and easy to maintain.

Secure consignment creation

When creating a consignment, the ownerId, teamId, and orgId are always derived from the authenticated user’s claims, preventing spoofing from client-side requests.

By always deriving sensitive attributes like ownerId, teamId, and orgId from the authenticated user’s claims, the backend enforces trust boundaries. Clients cannot override these fields, reducing the attack surface.

export const createConsignmentController = async (req: Request, res: Response) => {
  try {
    const consignmentData = {
      ...req.body,
      ownerId: req.user.sub,
      teamId: req.user.metadata?.teamId,
      orgId: req.user.tenantId
    };
    const consignment = await createConsignment(consignmentData);
    res.status(201).json(consignment);
  } catch (error) {
    res.status(400).json({ message: 'Failed to create consignment', error: error?.message });
  }
};

When a user with the SeniorManager role creates a consignment via the API, the backend automatically enriches the payload with the user’s organization, team, and ownership attributes, ensuring trust and consistency.

{
  "_id": "665d3eaf3fb8e9a6a210f4d3",
  "product": "Test Product",
  "quantity": 100,
  "source": "Nairobi, Kenya",
  "destination": "Paris, France",
  "status": "Processing",
  "ownerId": "6360a2d2-4418-4942-8d61-30a9c1328229",
  "teamId": "teamA",
  "orgId": "7b575a47-9519-4ae3-b548-395a24df6aee"
}

This response ensures that:

  • ownerId is always tied to the authenticated user’s sub claim.
  • teamId and orgId are derived from the Frontegg session and cannot be spoofed by the client.
  • The consignment is now fully traceable and securely associated with the user’s organization and team.

Frontend: User authentication

Users authenticate on the frontend app using Frontegg’s Next.js SDK, receiving a JWT Access Token containing:

  • sub (User ID)
  • tenantId (Organization ID)
  • metadata.teamId (Team ID)
  • roles

This token is sent with every API request using the Authorization: Bearer header.

Frontend: Passing the access token to the backend

In the Next.js frontend, we use the useAuth() hook to retrieve the accessToken, which is attached to API calls:

const { accessToken } = useAuth();

const res = await axios.get('/api/consignments', {
  headers: {
    Authorization: `Bearer ${accessToken}`
  }
});

Conclusion

By combining Frontegg’s role management with attribute-aware authorization logic on the backend, we demonstrated how modern authorization models can:

  • Support hierarchical roles like Senior managers, Managers, and ICs
  • Enforce dynamic attribute checks (e.g., ownerId, teamId, orgId) in your API
  • Prevent client-side spoofing of sensitive attributes
  • Keep your authorization logic clean, auditable, and scalable

With Frontegg handling the heavy lifting of authentication, role management, and session propagation, you can focus on what matters: applying your business logic and protecting your data.

This model isn’t limited to logistics—the same principles apply to finance, healthcare, and any SaaS platform where contextual access decisions are critical.

Try the demo

Ready to implement your own RBAC + ABAC authorization model? We’ve got options for you: