In this article
March 26, 2025
March 26, 2025

How to choose the right authorization model for your SaaS

Not sure which authorization model is best for your SaaS app? Our latest article breaks down the top approaches—from simple roles to Fine-Grained Authorization—helping you choose the right fit for your app's security and user management.

Authorization decides what users can access and what actions they can take. With the growing complexity of user roles, data privacy concerns, and ever-evolving business requirements, adopting an authorization model that balances flexibility with security is essential.

But how do you decide which model is best for your app? Should you use a simple role-based system or implement a more nuanced, fine-grained approach that accounts for user attributes, relationships, and policies? The answer depends on your application's and users' specific needs.

In this article, we'll explore several popular authorization models—ranging from role-based systems to more complex strategies like Fine-Grained Authorization (FGA)—to help you understand their pros, cons, and ideal use cases. By the end, you'll be ready to choose the right authorization model that perfectly fits your SaaS app's security, scalability, and user experience needs.

Roles: A simple starting point

The most basic form of access control is using roles. This is suitable if your users only need to be separated into broad categories and there is minimal overlap between roles. To do this, you can use role-based access control (RBAC). With RBAC, you assign users to roles (such as "Admin," "Editor," or "Viewer") and grant them access based on their role.

This model is suitable when there are well-defined and stable groups of users with clearly defined responsibilities. RBAC can be an easy and practical choice if the app's access requirements are straightforward and don't change frequently. It's handy for simple SaaS applications or where roles are hierarchical or organized into a few major categories.

However, RBAC can be too restrictive in smaller companies or startups, where roles are more fluid, and employees often wear multiple hats. It might block access to resources needed for tasks that don't neatly fall within an employee's main role. If your business environment changes frequently, you could constantly update roles, which is an administrative headache and can significantly delay things.

An example app for this authorization model is a simple blog platform where users have different responsibilities based on their roles:

  • Admin: Has full access to all content, user management, and settings.
  • Editor: Can create and edit content but cannot change settings or manage users.
  • Viewer: Can only read/view content but cannot make changes.

As you can understand, this model is too broad. For example, it gives the Editor the right to edit content, but it doesn't specify which content they should be allowed to edit. Can they only edit blogposts, or can they also delete comments? That's why roles are rarely used alone and are often enhanced by the user of permissions.

Roles and permissions: Adding granularity with specific actions

This model extends RBAC by adding more granularity. In addition to assigning users to roles, you can also define specific permissions for each role, such as create, read, update, and delete (CRUD). Permissions can be assigned directly to roles or specific users. When you use permissions, you don't need to maintain manual logic for each role; your app should only care about a user's permissions. They are particularly useful when:

  • You need to modify access rights or introduce new roles frequently.
  • There is a significant overlap in access rights between different roles, but there are some variations.
  • You want to minimize code changes when modifying access rights. By abstracting access control checks to permissions, you can add or modify roles and their access rights without changing the application code.

This model is appropriate when roles alone don't offer enough flexibility, and you need to control specific actions users can perform within the app. It's helpful when an app needs to differentiate user access to different resources (e.g., read-only access to one part of the app but full access to another). It also works well when roles can be flexible or dynamic, allowing for fine-tuned control over access rights. However, this model can still feel too restrictive for startups, where roles are more fluid.

An example of using roles with permissions is a tool for collaborative teams that need control over who can create, edit, or delete tasks. Permissions provide more granular control over what each user can do within the project, in addition to their role. Assuming we have three roles, project manager, team member, and viewer, the permissions might look like this:

  • Project manager:
    • create_task
    • edit_task
    • delete_task
    • view_task
    • assign_task.
  • Team member:
    • view_task
    • update_task
  • Viewer:
    • view_task

Although this model is more flexible than using roles alone, permissions are still tied to roles and are typically static. Most SaaS need more dynamic and granular control that can consider a combination of factors. That's when attributes, relationships, and policies come into play.

Attributes: Building a dynamic model with context

Attribute-based access control (ABAC) decides access based on user attributes (like department, job title, or location) or resource attributes (e.g., data sensitivity level). Permissions are granted based on a combination of these attributes, creating a more flexible and dynamic system.

ABAC is great for situations where roles and permissions aren't enough to cover all access rules. It's especially helpful for large apps with different types of users and resources, like multi-tenancy apps or systems that need to control access based on data (e.g., healthcare apps where access depends on the department or data sensitivity).

An example is a healthcare system where access to patient records is determined not only by the user's role (like doctor, nurse, admin) but also by the sensitivity of the data they need to access and their clearance level. ABAC helps ensure that a user can only see the data relevant to them based on specific attributes, like a user's department and clearance level:

  • User attributes:
    • department: Radiology
    • clearance_level: High
  • Resource attributes:
    • data_sensitivity: High
    • data_type: Patient Records

Some example access control rules might be:

  • Users in the Radiology department can view patient records related to radiology.
  • Only users with high clearance levels can access sensitive patient data.

The problem with ABAC is that as your system grows, you might need to track many attributes (like job roles, departments, and locations), leading to complex and hard-to-maintain access rules. An alternative is to consider simplifying things by using the relationships between users and resources (like team membership or project assignments).

Relationships: Using data connections to decide access

Relationship-based access control (ReBAC) focuses on the relationships between users, resources, and other entities. Users may have access to resources based on how they relate to other users or objects (e.g., a project manager can access the resources of a project they are managing).

ReBAC is often used in social media platforms, collaboration tools, or enterprise systems, where the relationship between a user and a resource (such as being a friend, colleague, or team member) is key to determining access. For example, in a collaborative platform where access to resources is based on ownership or team membership, ReBAC can model these relationships naturally.

A ReBAC example is a CRM where access to customer data is determined by the relationship a user has with that customer. Sales representatives only have access to accounts they are responsible for, while their managers have access to all accounts within their team or region:

  • User: Sales Rep A is assigned to Account X.
  • Relationship: The sales rep has a relationship with Account X, so they can view and edit its details.
  • Manager: The Sales Manager has a relationship with all accounts in their region, so they can view/edit all accounts within that region.

This could look like that using ReBAC:

	
{
  "relationships": {
    "SalesRepA": {
      "Account X": "responsible"
    },
    "SalesManager1": {
      "Account X": "manager",
      "Account Y": "manager"
    }
  },
  "permissions": {
    "view": [
      "responsible",
      "manager"
    ],
    "edit": [
      "responsible",
      "manager"
    ]
  }
}
	

ReBAC is generally stateful because it relies on dynamic relationships between users and resources. In ReBAC, access control decisions are made based on the relationships a user has with a particular resource (e.g., “Sales Rep A is assigned to Account X”). These relationships need to be stored and maintained to evaluate access permissions correctly. Therefore, the system needs to retain state to manage these relationships and grant access accordingly.

Policies: Adapt to changing conditions

Policies are rule-based models that define access control using logical statements or expressions. A policy could specify that "employees in the HR department can access employee records" or "only managers can approve vacation requests." These rules can be dynamic and may incorporate a combination of roles, attributes, and relationships.

With policy-based authorization, we can adapt our access control to changing conditions: I might be able to access certain sensitive reports from my office Monday through Friday, but I cannot access them from my home computer during the weekend.

Policies are most useful when the authorization logic requires flexibility and complexity that goes beyond what roles or attributes alone can provide. If your SaaS app has conditional or environment-dependent access needs (e.g., policies that change based on time, location, or user state), using policies is an effective way to express those rules. It also allows for more scalable and decentralized access control management.

An example is a leave approval system with complex conditions like specific timeframes, leave balances, and user roles. Policies enable rules that go beyond just the user's role and involve conditions like business rules, data attributes (leave balance), or time-based factors. For example:

  • Policy: "Managers can approve or deny vacation requests only if the employee's leave balance is sufficient, and the request is made at least 30 days in advance."
  • Rules:
    • A manager can approve vacation if the employee's leave balance is greater than 0 and if the request is made with at least 30 days' notice.
    • A policy rule could also specify that only managers can approve vacation requests.

This could be expressed using Cedar -AWS's policy language- as follows:

	
# Define the policy for leave approval
policy LeaveApproval {
    # Only managers can approve leave requests
    principal hasRole "manager"

    # The request can be approved if the leave balance is sufficient
    condition request.leave_balance > 0

    # The request must be made at least 30 days in advance
    condition request.request_date <= currentDate - 30
}

# Example input structure:
# {
#     "request": {
#         "leave_balance": 5,
#         "request_date": "2025-04-01",
#         "requested_leave_date": "2025-06-01"
#     },
#     "principal": {
#         "role": "manager"
#     },
#     "currentDate": "2025-03-01"
# }
	

Some of the problems of policies-based access control are performance overhead (since potentially complex policies are evaluated at runtime), the steep learning curve of writing and managing policies in specialized languages like Rego or Cedar, and the auditing difficulties in a microservices architecture where policies are often distributed across multiple services.

Combine all of the above with WorkOS FGA

The models described in this article are not mutually exclusive but are often used together. Combining roles, permissions, attributes, relationships, and policies results in a comprehensive, flexible, and fine-grained authorization model. This is where Fine-Grained Authorization (FGA) comes into play, allowing you to define access control rules based on a combination of all these factors, offering highly detailed control over who can access what and under what conditions.

FGA is an advanced access control model that considers several factors to decide whether a user should have access to a resource. These factors may include a user's role, seniority, location, or time of day. This allows you to tailor each user's access to the resources they need and thus tighten security.

This model suits complex applications with diverse and constantly changing access control requirements. It's perfect for organizations that must enforce sophisticated security rules and policies while ensuring that users have the right access based on a combination of factors. This is especially useful in enterprise-level SaaS apps, where users interact with varied resources across different levels of the organization and where access rules must adapt to complex business needs.

An example is a large financial application where multiple factors—roles, attributes (e.g., account type), relationships (e.g., departments or teams), and complex policies—combine to control access at a granular level. This is where FGA (Fine-Grained Authorization) shines, allowing you to define nuanced rules that consider all aspects of the user's role, relationships, and data attributes. The access control model might look like this:

  • Roles: Admin, Accountant, Manager, Client.
  • Attributes: Account type (e.g., Premium, Standard), region, transaction type.
  • Relationships: A Manager can view accounts that are related to their department.
  • Policies: A policy like “Managers can only approve transactions within their department's budget” or “Clients can view only their own transactions”.

Example scenario:

  • Admin can see all accounts and transactions.
  • Accountant can view and modify financial data but only for Premium clients.
  • Managers can only approve transactions related to their department based on the relationship they have with those accounts.
  • Clients can only see their own transaction records.

To implement your model with WorkOS FGA follow these steps:

  1. Define the schema: An FGA schema defines what kinds of resources exist in an application, what permissions users can have on those resources, and how permissions can be inherited under certain conditions.
  2. Create the resources and specify relationships and policies using warrants: Warrants are access rules that specify relationships between the resources in your application (e.g. [store:A] is [parent] of [item:123]). You can optionally add policies to evaluate at runtime.
  3. Make authorization checks at scale: You are now ready to make add access checks in our app by calling the WorkOS FGA API every time you need to. There are different endpoints you can use to check if a user has a specific permissionor to list all the permissions of a user.

For step-by-step guides and code samples, see our docs or our From RBAC to Fine-Grained Authorization guides.

Summary

Hopefully by now you have more clarity on which option is best for your app. When making your choice make sure to evaluate not only what your needs are today but what they will be in the future and how fast you plan to get there.

To sum up the options you have when it comes to access control models for your SaaS app:

  • Use roles if you have a simple app with well-defined, stable user categories.
  • Use roles and permissions if your app needs slightly more granular control over user actions within different parts of the system.
  • Use attributes for apps where user access needs to depend on various user attributes or resource properties (e.g., CRM systems where users' permissions depend on account type or region).
  • Use relationships for apps with complex relationships between entities (e.g., social networks, team collaboration tools).
  • Use policies for apps that require fine-grained, dynamic, and customizable access control (e.g., compliance-heavy platforms, financial apps).
  • Support all of of the above with WorkOS FGA for complex, large-scale apps requiring a highly detailed and adaptive authorization system.

This site uses cookies to improve your experience. Please accept the use of cookies on this site. You can review our cookie policy here and our privacy policy here. If you choose to refuse, functionality of this site will be limited.