Modeling Roles in MongoDB
Stamping the Wristband
Section titled “Stamping the Wristband”For our authorization logic to function, the assigned role must be persistently tracked inside the database. When a user successfully executes the login validation cycle, Passport fetches the entire User document and attaches it directly to the req.user object payload.
By adding the role directly into the document layout, the authorization validation effortlessly occurs entirely in memory by instantly referencing req.user.role.
Refining the User Schema
Section titled “Refining the User Schema”We implement this utilizing a native Mongoose String definition, heavily restricted by an explicit enum array mapping to our three target application roles.
const mongoose = require("mongoose");const Schema = mongoose.Schema;
const UserSchema = new Schema( { name: { type: String, required: true }, email: { type: String, required: true, unique: true }, passwordHash: { type: String, required: true },
// NEW ADDITION: The Role Enum role: { type: String, // The enum restricts the allowed values exclusively to this specific array enum: ["USER", "MODERATOR", "ADMIN"], // We default new registrations to the safest, lowest tier default: "USER", }, }, { timestamps: true },);
const User = mongoose.model("User", UserSchema);
class UserOps { // ... existing auth methods ...}
module.exports = new UserOps();Professor Solo: The enum acts essentially as a rigid database-level
spellchecker. If you attempt executing a query modifying a user’s role string
to "administrater" or "EDITOR", Mongoose will violently throw a
ValidationError exception, blocking the operation entirely.
Single Role vs Array of Roles
Section titled “Single Role vs Array of Roles”For 99% of straightforward web applications, assigning a singular, explicit role string (role: 'MODERATOR') exclusively manages the operational requirement impeccably.
If your requirements aggressively expand, requiring intersecting segmented responsibilities (e.g. they need to be a “Forum Moderator” AND a “Finance Admin”), the architecture easily transitions toward utilizing an explicit String array. However, we do not need that complexity here.
T.A. Watts Note: Do not over-engineer an array of roles before you demonstrably require them. Start small and simple. A single string is vastly easier to evaluate in middleware than iterating through an array.
With the data structurally ready to support our matrix, we will construct the protective middleware defending the actual Express routes.
⏭ Next: Admin User Inventory
Section titled “⏭ Next: Admin User Inventory”The database knows who is who. Before we build our bouncers, let’s build a unified dashboard so we can actually manage these accounts!