<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dennis Ogweno</title>
    <description>The latest articles on DEV Community by Dennis Ogweno (@d_lynol).</description>
    <link>https://dev.to/d_lynol</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F924862%2F25a9e7b6-40e3-4bb2-956a-15cddbe1a54a.png</url>
      <title>DEV Community: Dennis Ogweno</title>
      <link>https://dev.to/d_lynol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/d_lynol"/>
    <language>en</language>
    <item>
      <title>Stop Hardcoding Roles: A Practical Guide to Roles, Permissions, and Scalable Authorization</title>
      <dc:creator>Dennis Ogweno</dc:creator>
      <pubDate>Mon, 08 Jun 2026 15:57:26 +0000</pubDate>
      <link>https://dev.to/d_lynol/stop-hardcoding-roles-a-practical-guide-to-roles-permissions-and-scalable-authorization-1cf</link>
      <guid>https://dev.to/d_lynol/stop-hardcoding-roles-a-practical-guide-to-roles-permissions-and-scalable-authorization-1cf</guid>
      <description>&lt;p&gt;We've all been there.&lt;/p&gt;

&lt;p&gt;Your first encounter with authorization looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ADMIN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// allow access&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works.&lt;/p&gt;

&lt;p&gt;It's simple.&lt;/p&gt;

&lt;p&gt;It ships fast.&lt;/p&gt;

&lt;p&gt;And then, three months later, your application has grown, requirements have shifted, and you're staring at a codebase where authorization logic is scattered everywhere—APIs, services, UI components—like a puzzle that nobody remembers how to solve.&lt;/p&gt;

&lt;p&gt;The truth is: this approach doesn't scale.&lt;/p&gt;

&lt;p&gt;Not because it's inherently flawed, but because it conflates two very different concepts that should never be mixed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Core Mistake: Confusing Identity with Capability
&lt;/h2&gt;

&lt;p&gt;Here's the problem we're actually trying to solve.&lt;/p&gt;

&lt;p&gt;As your application grows, you inevitably end up writing code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BRANCH_MANAGER&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SYSTEM_ADMIN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// allow access&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then a stakeholder asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can we create a hybrid role?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We need Auditors who can export reports but not edit records.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And suddenly your role logic explodes into an unmaintainable mess.&lt;/p&gt;

&lt;p&gt;The fix isn't adding more conditions.&lt;/p&gt;

&lt;p&gt;The fix is understanding that &lt;strong&gt;roles&lt;/strong&gt; and &lt;strong&gt;permissions&lt;/strong&gt; answer fundamentally different questions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Roles Define Identity
&lt;/h2&gt;

&lt;p&gt;Roles are categories of users.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SYSTEM_ADMIN
CLIENT
BRANCH_MANAGER
AUDITOR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Roles answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Who is this user?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They establish high-level authorization boundaries.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Staff Portal vs Customer Portal&lt;/li&gt;
&lt;li&gt;Internal Admin Area vs Public Application&lt;/li&gt;
&lt;li&gt;Employee Features vs Client Features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of roles as &lt;strong&gt;identity labels&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Permissions Define Capability
&lt;/h2&gt;

&lt;p&gt;Permissions represent atomic actions.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LOAN_APPROVE
USER_DELETE
REPORT_EXPORT
ACCOUNT_EDIT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Permissions answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What can this user actually do?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your application should not constantly ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What role are you?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, it should ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do you have permission to perform this action?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Users have Roles
Roles contain Permissions
Code checks Permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That distinction changes everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  Always Decouple Identity from Capability
&lt;/h2&gt;

&lt;p&gt;This is one of the most important principles in authorization design.&lt;/p&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ADMIN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USER_DELETE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your code doesn't care whether the user is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ADMIN&lt;/li&gt;
&lt;li&gt;SUPER_ADMIN&lt;/li&gt;
&lt;li&gt;SUPPORT_MANAGER&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As long as they possess the required capability.&lt;/p&gt;

&lt;p&gt;That's flexibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Authorization Pyramid
&lt;/h2&gt;

&lt;p&gt;Instead of building one giant authorization mechanism, think in layers.&lt;/p&gt;

&lt;p&gt;Each layer should answer exactly one question.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authentication
      ↓
Role Boundary
      ↓
Permission Check
      ↓
Business Verification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break that down.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Authentication
&lt;/h2&gt;

&lt;p&gt;Question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are you who you claim to be?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT validation&lt;/li&gt;
&lt;li&gt;Session validation&lt;/li&gt;
&lt;li&gt;OAuth verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;401 Unauthorized
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Role Boundary
&lt;/h2&gt;

&lt;p&gt;Question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are you allowed into this area of the system?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Staff Portal
Customer Portal
Admin Dashboard
Partner Portal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A customer should never reach internal administration routes.&lt;/p&gt;

&lt;p&gt;An employee should never be redirected into customer-only experiences.&lt;/p&gt;

&lt;p&gt;This is where role checks make sense.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Permission Check
&lt;/h2&gt;

&lt;p&gt;Question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can you perform this specific action?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Approve Loan
Export Report
Delete User
Create Invoice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where permissions shine.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Business Verification
&lt;/h2&gt;

&lt;p&gt;Question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does the current system state allow this action?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the account verified?&lt;/li&gt;
&lt;li&gt;Is the loan eligible?&lt;/li&gt;
&lt;li&gt;Is the subscription active?&lt;/li&gt;
&lt;li&gt;Is the invoice already paid?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that this has nothing to do with authentication or authorization.&lt;/p&gt;

&lt;p&gt;It's business logic.&lt;/p&gt;

&lt;p&gt;Keep it separate.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Preferred Backend Flow
&lt;/h2&gt;

&lt;p&gt;I prefer enforcing authorization through middleware or interceptors before business logic executes.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RequirePermission&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LOAN_APPROVE"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Loan&lt;/span&gt; &lt;span class="nf"&gt;approveLoan&lt;/span&gt;&lt;span class="o"&gt;(...)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
  ↓
JWT Validation
  ↓
Role Boundary Check
  ↓
Permission Check
  ↓
Controller
  ↓
Business Logic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the permission is missing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;403 Forbidden
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before any business code executes.&lt;/p&gt;

&lt;p&gt;This keeps controllers clean and authorization centralized.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Illusion of Frontend Security
&lt;/h2&gt;

&lt;p&gt;Here's a hard truth.&lt;/p&gt;

&lt;p&gt;Frontend guards are about &lt;strong&gt;user experience&lt;/strong&gt;, not security.&lt;/p&gt;

&lt;p&gt;This:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USER_DELETE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;renderDeleteButton&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;does not secure anything.&lt;/p&gt;

&lt;p&gt;It simply hides a button.&lt;/p&gt;

&lt;p&gt;Anyone can still attempt to call the API.&lt;/p&gt;

&lt;p&gt;Which means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every authorization rule enforced on the frontend must also be enforced on the backend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Always.&lt;/p&gt;

&lt;p&gt;The backend is the source of truth.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hide or Disable?
&lt;/h2&gt;

&lt;p&gt;This is often debated.&lt;/p&gt;

&lt;p&gt;Some teams prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Disabled button
Tooltip explaining why
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Others prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hide the action entirely
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Personally, I favor hiding actions users cannot perform.&lt;/p&gt;

&lt;p&gt;If a user lacks permission to delete records, I generally don't show the delete action at all.&lt;/p&gt;

&lt;p&gt;A cleaner interface creates less confusion and reduces cognitive load.&lt;/p&gt;

&lt;p&gt;That said, accessibility and transparency requirements may lead some teams toward disabled controls.&lt;/p&gt;

&lt;p&gt;Choose deliberately.&lt;/p&gt;




&lt;h2&gt;
  
  
  Move Authorization State Into the Database
&lt;/h2&gt;

&lt;p&gt;Hardcoding role-permission mappings in code works for prototypes.&lt;/p&gt;

&lt;p&gt;Eventually it becomes technical debt.&lt;/p&gt;

&lt;p&gt;Instead, use a relational model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users
  ↓
user_roles
  ↓
roles
  ↓
role_permissions
  ↓
permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic administration&lt;/li&gt;
&lt;li&gt;Auditability&lt;/li&gt;
&lt;li&gt;Flexibility&lt;/li&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;li&gt;Reduced deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Need a new role?&lt;/p&gt;

&lt;p&gt;Add it in the database.&lt;/p&gt;

&lt;p&gt;Need a new permission?&lt;/p&gt;

&lt;p&gt;Add it in the database.&lt;/p&gt;

&lt;p&gt;Need a custom role for a specific customer?&lt;/p&gt;

&lt;p&gt;No code changes required.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Authorization Flow
&lt;/h2&gt;

&lt;p&gt;A common production architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Logs In
      ↓
Backend Loads Roles
      ↓
Backend Resolves Permissions
      ↓
JWT Created
      ↓
Frontend Receives JWT
      ↓
UI Renders Appropriate Features
      ↓
Backend Revalidates Every Request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example JWT payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"LOAN_APPROVE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"REPORT_EXPORT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"USER_VIEW"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend uses these permissions to drive UX.&lt;/p&gt;

&lt;p&gt;The backend uses them to enforce security.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Requirements Inevitably Change
&lt;/h2&gt;

&lt;p&gt;And they will.&lt;/p&gt;

&lt;p&gt;A stakeholder will ask for:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An Auditor role that can export reports but cannot edit records.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Later:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We need a Compliance Auditor with one extra permission.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With hardcoded role logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Refactor
Test
Redeploy
Hope nothing breaks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With database-driven permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create Role
Assign Permissions
Done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No deployment.&lt;/p&gt;

&lt;p&gt;No code change.&lt;/p&gt;

&lt;p&gt;No risk.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Principle That Wins
&lt;/h2&gt;

&lt;p&gt;The core insight is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Decouple who the user is from what the system allows them to do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you separate identity from capability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture stays predictable&lt;/li&gt;
&lt;li&gt;Authorization becomes composable&lt;/li&gt;
&lt;li&gt;Requirements become easier to accommodate&lt;/li&gt;
&lt;li&gt;Security becomes easier to reason about&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Roles define boundaries.
Permissions define actions.
Code checks permissions.
Backend enforces everything.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything else follows from that.&lt;/p&gt;

&lt;p&gt;How do you handle authorization in your applications: hardcoded roles, permissions, a hybrid RBAC model, or something else entirely? What trade-offs have you encountered as your system scaled?&lt;/p&gt;

</description>
      <category>react</category>
      <category>uidesign</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
