Role-Based Authorization

Role-Based Access Control (RBAC) assigns permissions through roles.

For example:

CUSTOMER
SUPPORT
ADMIN

The schema might expose:

enum Role {
  CUSTOMER
  SUPPORT
  ADMIN
}

type User {
  id: ID!
  role: Role!
}

A resolver can enforce a role requirement:

function requireRole(context, allowedRoles) {
  if (!context.user) {
    throw new Error("Authentication required");
  }

  if (!allowedRoles.includes(context.user.role)) {
    throw new Error("Forbidden");
  }
}

Then:

const resolvers = {
  Mutation: {
    deleteUser: (_, { id }, context) => {
      requireRole(context, ["ADMIN"]);
      return context.userService.deleteUser(id);
    }
  }
};

RBAC is easy to understand, but roles can become too coarse as an application grows.

For example, saying that every SUPPORT user can update every customer record may be too broad. Real applications often need resource-level or attribute-level authorization as well.

Example Roles
CUSTOMER: Own account and customer operations
Usually has permissions limited to resources belonging to the user.
SUPPORT: Customer support operations
May have access to customer records without administrative capabilities.
ADMIN: Administrative operations
May have broad management permissions depending on the application's policy.
Key Takeaways
  • RBAC assigns permissions through roles.
  • Role checks are simple and useful for many applications.
  • Roles can become too broad for resource-specific authorization.
  • Authorization should reflect actual business rules.
Knowledge Check

What is the main idea behind RBAC?