Roles and Permissions

Welcome to this tutorial on Roles and Permissions. In many applications, ensuring that only authorized users can take specific actions is vital for data integrity and security. Think of this like having a ticket to a concert: not everyone can walk backstage, only those with the correct pass (permission) or the correct badge (role) can get in.

By the end of this lesson, you will be able to:

Let’s explore how this might apply to real-world scenarios, such as a photographer's online system, and later discuss where these concepts might fit in your own projects.

What are User Permissions?

A user permission is an authorization that allows a user to perform a particular action on the server or application. It’s like a personal key that opens a specific door.

For instance, imagine you have a system for storing a professional photographer's photographs. The photographer (or admin) might have these four permissions:

On the other hand, Customer A might have just one permission:

Notice how permissions are very specific actions. They define exactly what a user can do.

What are User Roles?

A user role is a collection of permissions bundled together. Think of a role like a membership level. Multiple people can share that membership, and they all inherit the same perks (permissions).

For example, you might have the Admin Role, which includes the following permissions:

Then you might have a Customer Role with these permissions:

And finally, maybe a Guest Role that only allows:

Think of it this way: if you’re labeled an “Admin,” you automatically get all the Admin permissions; if you’re labeled a “Customer,” you get a more restricted set of permissions, and so on. Roles help you scale your permission system because you don’t have to assign each permission individually to every user.

User Roles vs. Permissions

Although roles and permissions are closely related, they differ in that a permission is a specific privilege for a single user, while a role is a bundle of such permissions that can be applied to many users at once.

In an application, you might have logic to check if a user has a certain permission before performing an action. In pseudocode, it might look like this:

if (currentUserHasThisPermission) {
  // get all photo urls from photo table
} else {
  // display error message "You are not authorized to access that resource"
}

In a role-based system, you’d often store a user’s role in a users table (for example, isAdmin, isCustomer, or roleType column). Then the logic to check permissions becomes:

if (currentUserRole === 'Admin') {
  // do admin stuff, like view or update all photos
} else if (currentUserRole === 'Customer') {
  // do customer stuff, limited to their own photos
} else {
  // guest or no role: limited access
}

Assigning a role is simpler in practice than assigning a huge list of permissions one by one. However, some systems need the fine-grained control of individual permissions. It all depends on your application’s complexity.

Step by Step Example / Follow-Along Exercise

Let’s walk through a simplified example step by step, assuming you’re using a Sequelize-based Node.js backend and have a Users table with columns for email, password, and role (which could be "admin", "customer", or "guest").

Step: Define your User model with a role attribute:

const User = sequelize.define('User', {
  email: {
    type: DataTypes.STRING,
    unique: true,
    allowNull: false
  },
  password: {
    type: DataTypes.STRING,
    allowNull: false
  },
  role: {
    type: DataTypes.STRING,
    allowNull: false, // "admin", "customer", or "guest"
    defaultValue: "guest"
  }
});

Step: Seed your database with a few users, each having a different role:

// Example of creating users with roles

await User.create({
  email: 'photo_pro@example.com',
  password: 'super_secret',
  role: 'admin'
});

await User.create({
  email: 'john_customer@example.com',
  password: 'dont_hack_me',
  role: 'customer'
});

await User.create({
  email: 'random_guest@example.com',
  password: 'i_am_a_guest',
  role: 'guest'
});

Step: In your route handler or controller, check the user’s role before performing operations:

// Example route to delete a photo
app.delete('/photos/:id', async (req, res) => {
  const currentUser = req.user; // assume this is populated from a login token/session

  // Only admin role can delete any photo
  if (currentUser.role === 'admin') {
    // perform the delete operation...
    await Photo.destroy({ where: { id: req.params.id } });
    res.sendStatus(200);
  } else {
    res.status(403).json({ message: 'Forbidden: Insufficient permissions.' });
  }
});

In this snippet, we simply check the role and decide if the action is allowed. A more sophisticated approach could combine role checks with ownership checks (e.g., a customer might delete only their own photos).

Real World Example

Think about large e-commerce platforms:

Each role has a different scope of what they can do. This keeps the marketplace secure and prevents unauthorized changes.

When and Why to Use Roles and Permissions

Use roles and permissions in any scenario where you have different “types” of users who need distinct privileges. Common scenarios include:

Roles and permissions ensure a safer and more organized application, especially as your user base grows.

Further Topics to Explore

As you dig deeper, you’ll find advanced patterns that let you handle highly complex permissions. Often, these systems need to be carefully designed to remain both flexible and maintainable.

What You Learned

Defining roles and permissions in your application is essential for ensuring data privacy and correct access control. Remember these key takeaways:

By carefully structuring roles and permissions, you can scale your application’s security and ensure that each user has the right level of access—no more, no less.