<?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: Muhammad Masood Kausar</title>
    <description>The latest articles on DEV Community by Muhammad Masood Kausar (@masaood).</description>
    <link>https://dev.to/masaood</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4038284%2F32413a21-1e19-4677-a6c7-e7bd4c31dc7a.png</url>
      <title>DEV Community: Muhammad Masood Kausar</title>
      <link>https://dev.to/masaood</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/masaood"/>
    <language>en</language>
    <item>
      <title>The Overengineering Trap We All Fall Into</title>
      <dc:creator>Muhammad Masood Kausar</dc:creator>
      <pubDate>Wed, 22 Jul 2026 09:49:24 +0000</pubDate>
      <link>https://dev.to/masaood/the-overengineering-trap-we-all-fall-into-2md5</link>
      <guid>https://dev.to/masaood/the-overengineering-trap-we-all-fall-into-2md5</guid>
      <description>&lt;p&gt;The most dangerous overengineering does not look careless.&lt;/p&gt;

&lt;p&gt;It looks thoughtful.&lt;/p&gt;

&lt;p&gt;It has clean interfaces, reusable components, configurable behavior, extension points, and an architecture diagram that makes the system appear ready for anything.&lt;/p&gt;

&lt;p&gt;Then the next feature arrives.&lt;/p&gt;

&lt;p&gt;A change that should take one afternoon touches seven layers, breaks three abstractions, and forces the team to understand a framework built for requirements that never appeared.&lt;/p&gt;

&lt;p&gt;That is what makes overengineering difficult to recognize.&lt;/p&gt;

&lt;p&gt;It rarely presents itself as unnecessary complexity. It presents itself as responsible engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  It Usually Begins With a Reasonable Fear
&lt;/h2&gt;

&lt;p&gt;Developers do not overengineer because they want to make systems harder.&lt;/p&gt;

&lt;p&gt;They usually remember an earlier project that became painful.&lt;/p&gt;

&lt;p&gt;Maybe duplicated business logic spread across several screens. Maybe a component could not support a second use case. Maybe an integration became impossible to replace. Maybe a narrow implementation eventually required an expensive rewrite.&lt;/p&gt;

&lt;p&gt;The next time a similar problem appears, the team tries to protect itself.&lt;/p&gt;

&lt;p&gt;What if this feature grows?&lt;/p&gt;

&lt;p&gt;What if another team needs it?&lt;/p&gt;

&lt;p&gt;What if product asks for configuration?&lt;/p&gt;

&lt;p&gt;What if we add more providers?&lt;/p&gt;

&lt;p&gt;What if the rules change?&lt;/p&gt;

&lt;p&gt;These are reasonable questions. The problem begins when imagined requirements receive the same architectural weight as real ones.&lt;/p&gt;

&lt;p&gt;A single approval flow becomes a workflow engine. Two similar components become a universal rendering framework. One pricing exception becomes a configurable rules platform.&lt;/p&gt;

&lt;p&gt;The team tries to avoid future pain and creates immediate friction instead.&lt;/p&gt;

&lt;p&gt;The first use case now has to support requirements that do not exist. Developers must understand extension points nobody uses, configuration nobody needs, and interfaces protecting boundaries that have not appeared.&lt;/p&gt;

&lt;p&gt;Thinking about the future is not the mistake.&lt;/p&gt;

&lt;p&gt;Building the future before there is evidence is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reuse Is Expensive Before the Pattern Is Stable
&lt;/h2&gt;

&lt;p&gt;Reusable code sounds like an obvious improvement.&lt;/p&gt;

&lt;p&gt;Nobody wants five versions of the same logic. Shared behavior can reduce bugs, improve consistency, and make future changes easier.&lt;/p&gt;

&lt;p&gt;But two pieces of code looking similar does not mean they represent the same concept.&lt;/p&gt;

&lt;p&gt;The first abstraction usually looks clean. It removes duplication and gives the codebase a shared component, service, or helper.&lt;/p&gt;

&lt;p&gt;Then another use case arrives.&lt;/p&gt;

&lt;p&gt;It needs a different loading state.&lt;/p&gt;

&lt;p&gt;The third needs different validation.&lt;/p&gt;

&lt;p&gt;The fourth has different permissions.&lt;/p&gt;

&lt;p&gt;Soon the reusable abstraction collects flags, callbacks, modes, configuration objects, and escape hatches.&lt;/p&gt;

&lt;p&gt;The code is technically reusable, but changing it safely now requires understanding every consumer.&lt;/p&gt;

&lt;p&gt;The team did not eliminate complexity. It concentrated complexity inside one shared dependency.&lt;/p&gt;

&lt;p&gt;Sometimes a little duplication is more honest.&lt;/p&gt;

&lt;p&gt;Duplication says, “These cases currently look similar, but we do not yet know whether they will change together.”&lt;/p&gt;

&lt;p&gt;A premature abstraction says, “We already understand the shared concept.”&lt;/p&gt;

&lt;p&gt;That confidence is often the expensive part.&lt;/p&gt;

&lt;p&gt;Good abstractions usually become obvious after several real use cases expose what remains stable. Before that, reuse is often based on visual similarity rather than shared responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Should Protect Real Pressure
&lt;/h2&gt;

&lt;p&gt;Architecture is valuable when it protects the system from something concrete.&lt;/p&gt;

&lt;p&gt;A service layer may protect business rules from HTTP concerns. An adapter may isolate an unstable third-party API. A repository may centralize complex persistence behavior. A policy module may prevent authorization rules from spreading everywhere.&lt;/p&gt;

&lt;p&gt;Those boundaries reduce meaningful pressure.&lt;/p&gt;

&lt;p&gt;But layers added only because mature systems are expected to have layers create a different result.&lt;/p&gt;

&lt;p&gt;A small feature gains controllers, services, repositories, mappers, interfaces, factories, validators, and adapters. Every file is small. Every class has one apparent responsibility.&lt;/p&gt;

&lt;p&gt;Then one field changes.&lt;/p&gt;

&lt;p&gt;The update must pass through an input type, controller, interface, service, mapper, repository, test fixture, and mock. The architecture looks organized, but ordinary changes feel like paperwork.&lt;/p&gt;

&lt;p&gt;A layer that protects nothing is not automatically good architecture.&lt;/p&gt;

&lt;p&gt;Sometimes it is ceremony.&lt;/p&gt;

&lt;p&gt;Before introducing another boundary, ask what kind of change it makes cheaper.&lt;/p&gt;

&lt;p&gt;Does it isolate something volatile?&lt;/p&gt;

&lt;p&gt;Does it clarify ownership?&lt;/p&gt;

&lt;p&gt;Does it prevent a failure the team has experienced?&lt;/p&gt;

&lt;p&gt;Does it remove repeated decisions?&lt;/p&gt;

&lt;p&gt;Does it make debugging more direct?&lt;/p&gt;

&lt;p&gt;Without a concrete answer, the architecture may be solving developer anxiety rather than product complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flexibility Creates a Decision Tax
&lt;/h2&gt;

&lt;p&gt;Flexible systems promise safety.&lt;/p&gt;

&lt;p&gt;They can support more rules, more providers, more workflows, more rendering modes, and more future variation.&lt;/p&gt;

&lt;p&gt;But every option introduces decisions.&lt;/p&gt;

&lt;p&gt;Should the next requirement become another configuration field?&lt;/p&gt;

&lt;p&gt;Should it be a new strategy?&lt;/p&gt;

&lt;p&gt;Does it belong inside the shared abstraction?&lt;/p&gt;

&lt;p&gt;Should the team add an escape hatch?&lt;/p&gt;

&lt;p&gt;Which combinations are valid?&lt;/p&gt;

&lt;p&gt;Who tests them?&lt;/p&gt;

&lt;p&gt;Who documents them?&lt;/p&gt;

&lt;p&gt;A system may support dozens of combinations while nobody understands which combinations are actually safe.&lt;/p&gt;

&lt;p&gt;That is not useful flexibility.&lt;/p&gt;

&lt;p&gt;It is uncontrolled variability.&lt;/p&gt;

&lt;p&gt;The hidden cost is not only additional code. It is the number of architectural decisions developers must make before completing ordinary product work.&lt;/p&gt;

&lt;p&gt;Instead of solving the requirement directly, they must first negotiate with the framework surrounding it.&lt;/p&gt;

&lt;p&gt;The best internal systems reduce unnecessary decisions for the next developer. They make the obvious path clear and safe.&lt;/p&gt;

&lt;p&gt;Overengineered systems make ordinary work require architectural judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Next Change Is the Real Test
&lt;/h2&gt;

&lt;p&gt;A design cannot be judged only by how clean it looks when first introduced.&lt;/p&gt;

&lt;p&gt;The real test is what happens when the requirement changes.&lt;/p&gt;

&lt;p&gt;Can the behavior be found quickly?&lt;/p&gt;

&lt;p&gt;Can one use case change without risking unrelated ones?&lt;/p&gt;

&lt;p&gt;Does the abstraction explain the business concept, or hide it?&lt;/p&gt;

&lt;p&gt;Can a developer trace a wrong value without walking through several indirection layers?&lt;/p&gt;

&lt;p&gt;Does the architecture make the change smaller, or merely distribute it across more files?&lt;/p&gt;

&lt;p&gt;This is where many impressive designs reveal their cost.&lt;/p&gt;

&lt;p&gt;They were optimized for the first implementation, the code review, or an imagined future. They were not optimized for the actual changes the product eventually required.&lt;/p&gt;

&lt;p&gt;The future often arrives, but rarely in the exact shape the original abstraction predicted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let Complexity Earn Its Structure
&lt;/h2&gt;

&lt;p&gt;The answer is not to reject architecture, reuse, or abstraction.&lt;/p&gt;

&lt;p&gt;Underengineering creates its own damage. Scattered rules, hidden dependencies, duplicated behavior, missing boundaries, and careless shortcuts can make a codebase equally painful.&lt;/p&gt;

&lt;p&gt;The better rule is simpler:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let complexity earn structure.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build the current behavior clearly.&lt;/p&gt;

&lt;p&gt;Keep important decisions visible.&lt;/p&gt;

&lt;p&gt;Protect boundaries that already matter.&lt;/p&gt;

&lt;p&gt;Avoid coupling that would make later extraction difficult.&lt;/p&gt;

&lt;p&gt;Then wait for real use cases to reveal what is genuinely shared.&lt;/p&gt;

&lt;p&gt;A good first version does not need to be careless. It can be readable, tested around meaningful risks, and arranged so future refactoring remains possible.&lt;/p&gt;

&lt;p&gt;It simply does not pretend to know the final architecture before the product has supplied enough evidence.&lt;/p&gt;

&lt;p&gt;Overengineering is not thinking about tomorrow.&lt;/p&gt;

&lt;p&gt;It is forcing today’s work to pay for a tomorrow that still exists only in our imagination.&lt;/p&gt;

&lt;p&gt;I explored the deeper debugging costs, decision overhead, scalability assumptions, and practical signals of premature abstraction in the complete essay:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://medium.com/@masaood/the-overengineering-trap-we-all-fall-into-4cca6fe46013" rel="noopener noreferrer"&gt;Read the full article on Medium: The Overengineering Trap We All Fall Into&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Have you worked with a future-proof design that eventually made simple changes harder?&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>architecture</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>The Node.js Shortcut That Quietly Created a Security Hole</title>
      <dc:creator>Muhammad Masood Kausar</dc:creator>
      <pubDate>Tue, 21 Jul 2026 07:46:18 +0000</pubDate>
      <link>https://dev.to/masaood/the-nodejs-shortcut-that-quietly-created-a-security-hole-4abo</link>
      <guid>https://dev.to/masaood/the-nodejs-shortcut-that-quietly-created-a-security-hole-4abo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;We verified who made the request, but never verified whether that user was allowed to access the requested resource.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The endpoint rejected unauthenticated requests, so we assumed it was secure.&lt;/p&gt;

&lt;p&gt;It was not.&lt;/p&gt;

&lt;p&gt;The route had authentication middleware. Invalid tokens returned &lt;code&gt;401&lt;/code&gt;. Expired sessions were rejected. The controller received a verified user.&lt;/p&gt;

&lt;p&gt;Everything looked protected.&lt;/p&gt;

&lt;p&gt;But an authenticated user could change the resource ID in the URL and access data belonging to another account.&lt;/p&gt;

&lt;p&gt;Authentication worked exactly as expected.&lt;/p&gt;

&lt;p&gt;Authorization was missing.&lt;/p&gt;

&lt;p&gt;That difference came down to one condition in a database query, but in the application’s security model, it was the entire boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Route Looked Secure
&lt;/h2&gt;

&lt;p&gt;The route looked like a normal protected Node.js endpoint:&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="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/documents/:documentId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;validateAccessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;attachCurrentUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getDocument&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The middleware performed all the expected work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;verified the access token&lt;/li&gt;
&lt;li&gt;rejected invalid sessions&lt;/li&gt;
&lt;li&gt;loaded the current user&lt;/li&gt;
&lt;li&gt;attached the user to the request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The controller only ran after authentication succeeded.&lt;/p&gt;

&lt;p&gt;That created a dangerous assumption:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authenticated request = trusted request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But authenticated users should not automatically be trusted with every resource in the application.&lt;/p&gt;

&lt;p&gt;A logged-in customer should not be able to read another customer’s invoice.&lt;/p&gt;

&lt;p&gt;A member of one organization should not be able to access another organization’s projects.&lt;/p&gt;

&lt;p&gt;A normal employee should not be able to approve an administrative request.&lt;/p&gt;

&lt;p&gt;A project viewer may be allowed to read a project but not delete it.&lt;/p&gt;

&lt;p&gt;Authentication answers one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Who is making this request?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Authorization answers another:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this user allowed to perform this action on this resource?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Identity is only an input to the authorization decision.&lt;/p&gt;

&lt;p&gt;It is not the decision itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shortcut Was Loading Records by ID Alone
&lt;/h2&gt;

&lt;p&gt;The controller accepted a resource ID from the URL:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;documentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&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;The service then loaded the record using only that ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;documentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;,&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;This code looked clean.&lt;/p&gt;

&lt;p&gt;It was easy to read.&lt;/p&gt;

&lt;p&gt;It also asked the wrong question.&lt;/p&gt;

&lt;p&gt;The query asked:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does a document with this ID exist?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It did not ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this document belong to the current user or account?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The database had no knowledge of the security boundary.&lt;/p&gt;

&lt;p&gt;For an account-scoped application, the query should include the account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;documentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;,&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;For user-owned resources, it might include &lt;code&gt;ownerId&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;documentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ownerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&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;For a multi-tenant system, it might include &lt;code&gt;tenantId&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;documentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;,&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;This is not just another database condition.&lt;/p&gt;

&lt;p&gt;It changes the meaning of the operation.&lt;/p&gt;

&lt;p&gt;The unsafe version means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find this document.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The scoped version means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find this document inside the boundary this user is allowed to access.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The database query should understand the security boundary, not only the resource identifier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Valid Token Made the Bug Harder to Notice
&lt;/h2&gt;

&lt;p&gt;Most authentication tests verify that anonymous users are rejected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rejects requests without a token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/documents/123&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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&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;This is useful, but it only proves that unauthenticated users cannot access the endpoint.&lt;/p&gt;

&lt;p&gt;A positive test may verify that the owner can access the document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allows the owner to access the document&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createDocument&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;ownerId&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/documents/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;createToken&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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;This test also passes.&lt;/p&gt;

&lt;p&gt;The missing scenario is the one that exposes the vulnerability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a real user&lt;/li&gt;
&lt;li&gt;a valid token&lt;/li&gt;
&lt;li&gt;a real resource&lt;/li&gt;
&lt;li&gt;the wrong owner
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;does not expose another user's document&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;otherUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createDocument&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;ownerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/documents/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;otherUser&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&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;The most valuable security test often uses a valid token belonging to the wrong user.&lt;/p&gt;

&lt;p&gt;This type of bug can also survive code review because authentication and data access usually live in different layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route
  → Middleware
    → Controller
      → Service
        → Repository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A reviewer sees the authentication middleware in the route file.&lt;/p&gt;

&lt;p&gt;Another reviewer sees a simple &lt;code&gt;findById&lt;/code&gt; method in the repository.&lt;/p&gt;

&lt;p&gt;Each piece looks reasonable in isolation.&lt;/p&gt;

&lt;p&gt;The vulnerability appears only when the complete request path is examined.&lt;/p&gt;

&lt;p&gt;The route proves identity.&lt;/p&gt;

&lt;p&gt;The controller accepts a client-controlled identifier.&lt;/p&gt;

&lt;p&gt;The repository loads the resource without ownership or tenant scoping.&lt;/p&gt;

&lt;p&gt;The response returns the result.&lt;/p&gt;

&lt;p&gt;Each file looked secure on its own.&lt;/p&gt;

&lt;p&gt;The security hole existed between them.&lt;/p&gt;

&lt;h2&gt;
  
  
  UUIDs Did Not Fix the Authorization Problem
&lt;/h2&gt;

&lt;p&gt;A common response to this vulnerability is to replace sequential IDs with UUIDs.&lt;/p&gt;

&lt;p&gt;Sequential IDs are easy to guess:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/documents/1001
/documents/1002
/documents/1003
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;UUIDs are much harder to enumerate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/documents/f9a81862-0db8-4f61-b7ea-9a74d97d71b4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can reduce predictable resource discovery.&lt;/p&gt;

&lt;p&gt;It does not create permission.&lt;/p&gt;

&lt;p&gt;A user may still obtain a valid identifier through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a copied URL&lt;/li&gt;
&lt;li&gt;browser history&lt;/li&gt;
&lt;li&gt;logs&lt;/li&gt;
&lt;li&gt;analytics&lt;/li&gt;
&lt;li&gt;notifications&lt;/li&gt;
&lt;li&gt;support tickets&lt;/li&gt;
&lt;li&gt;screenshots&lt;/li&gt;
&lt;li&gt;frontend state&lt;/li&gt;
&lt;li&gt;another API response&lt;/li&gt;
&lt;li&gt;another vulnerable endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When authorization is missing, possession of the identifier becomes possession of the resource.&lt;/p&gt;

&lt;p&gt;That is not a safe access model.&lt;/p&gt;

&lt;p&gt;A resource ID identifies an object.&lt;/p&gt;

&lt;p&gt;It does not grant permission to access it.&lt;/p&gt;

&lt;p&gt;A UUID can hide the door, but it cannot replace the lock.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Same Shortcut Affected More Than Read Endpoints
&lt;/h2&gt;

&lt;p&gt;Once a service exposes a generic method like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it often becomes the default lookup for several endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET    /documents/:id
PATCH  /documents/:id
DELETE /documents/:id
POST   /documents/:id/share
POST   /documents/:id/archive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The missing boundary may allow another authenticated user to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read private data&lt;/li&gt;
&lt;li&gt;update records&lt;/li&gt;
&lt;li&gt;delete content&lt;/li&gt;
&lt;li&gt;download attachments&lt;/li&gt;
&lt;li&gt;resend invitations&lt;/li&gt;
&lt;li&gt;trigger workflows&lt;/li&gt;
&lt;li&gt;change ownership&lt;/li&gt;
&lt;li&gt;modify billing information&lt;/li&gt;
&lt;li&gt;approve restricted actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authorization also depends on the requested action.&lt;/p&gt;

&lt;p&gt;A user may be allowed to read a project but not delete it.&lt;/p&gt;

&lt;p&gt;An editor may update a draft but not publish it.&lt;/p&gt;

&lt;p&gt;A manager may approve expenses only below a specific amount.&lt;/p&gt;

&lt;p&gt;A support agent may view customer details but not change payment information.&lt;/p&gt;

&lt;p&gt;A better authorization model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User + Action + Resource + Context = Authorization decision
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Valid token = Permission granted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Nested Routes Can Create False Confidence
&lt;/h2&gt;

&lt;p&gt;Nested URLs often look naturally secure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/projects/:projectId/comments/:commentId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The route appears to say that the comment belongs to the project.&lt;/p&gt;

&lt;p&gt;But the URL does not enforce that relationship.&lt;/p&gt;

&lt;p&gt;A controller may verify access to the project and then load the comment using only &lt;code&gt;commentId&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;commentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;commentId&lt;/span&gt;&lt;span class="p"&gt;,&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;That comment could belong to another project.&lt;/p&gt;

&lt;p&gt;The query should verify both identifiers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;commentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;commentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;,&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;The project itself must also exist inside the user’s permitted organization, account, or tenant.&lt;/p&gt;

&lt;p&gt;A nested URL does not prove the relationship.&lt;/p&gt;

&lt;p&gt;The data-access layer must enforce it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Fix Was Architectural
&lt;/h2&gt;

&lt;p&gt;The fastest fix may be a manual ownership check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ownerId&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ForbiddenError&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;That is better than no authorization.&lt;/p&gt;

&lt;p&gt;But repeating checks manually across controllers creates another problem.&lt;/p&gt;

&lt;p&gt;Eventually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one endpoint forgets the check&lt;/li&gt;
&lt;li&gt;one endpoint checks ownership but not tenancy&lt;/li&gt;
&lt;li&gt;one endpoint applies a different role rule&lt;/li&gt;
&lt;li&gt;one endpoint loads sensitive data before rejecting the request&lt;/li&gt;
&lt;li&gt;one endpoint handles administrators globally instead of per organization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authorization becomes duplicated business logic.&lt;/p&gt;

&lt;p&gt;Duplicated security logic eventually becomes inconsistent security logic.&lt;/p&gt;

&lt;p&gt;The stronger approach is to make authorization part of the resource-access design.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: Scoped repository methods
&lt;/h3&gt;

&lt;p&gt;For simple ownership or account rules, use methods that require the security boundary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findAccountDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;documentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&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;The method does not provide an easy way to load a document outside the current account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: Explicit policy services
&lt;/h3&gt;

&lt;p&gt;More complex permissions may need a dedicated authorization policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;documentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;authorizationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertCanReadDocument&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;document&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;This is useful when access depends on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ownership&lt;/li&gt;
&lt;li&gt;roles&lt;/li&gt;
&lt;li&gt;team membership&lt;/li&gt;
&lt;li&gt;organization membership&lt;/li&gt;
&lt;li&gt;resource state&lt;/li&gt;
&lt;li&gt;sharing rules&lt;/li&gt;
&lt;li&gt;subscription level&lt;/li&gt;
&lt;li&gt;administrative scope&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Option 3: Framework guards
&lt;/h3&gt;

&lt;p&gt;In NestJS, guards can handle authentication and high-level role checks.&lt;/p&gt;

&lt;p&gt;However, a generic role guard may not have enough information to make a resource-level decision.&lt;/p&gt;

&lt;p&gt;Knowing that a user has the role &lt;code&gt;manager&lt;/code&gt; does not prove that the user manages the organization that owns the requested document.&lt;/p&gt;

&lt;p&gt;Role authorization and resource authorization often need to work together.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 4: Database-level isolation
&lt;/h3&gt;

&lt;p&gt;Some applications use tenant-aware database clients or row-level security.&lt;/p&gt;

&lt;p&gt;This adds another layer of protection when application code forgets a filter.&lt;/p&gt;

&lt;p&gt;It can be powerful, but it also adds complexity. Policies must be observable, testable, and understood by the team.&lt;/p&gt;

&lt;p&gt;There is no single authorization design for every application.&lt;/p&gt;

&lt;p&gt;The important requirement is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The security boundary should be explicit, reusable, testable, and difficult to bypass accidentally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The safest authorization check is the one the application cannot easily forget to perform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Security Boundaries, Not Only Endpoints
&lt;/h2&gt;

&lt;p&gt;After finding this bug, the test strategy should change.&lt;/p&gt;

&lt;p&gt;Do not only test whether the endpoint works.&lt;/p&gt;

&lt;p&gt;Test which identities can perform which actions.&lt;/p&gt;

&lt;p&gt;A useful authorization matrix might look like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Expected result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No token&lt;/td&gt;
&lt;td&gt;&lt;code&gt;401&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invalid token&lt;/td&gt;
&lt;td&gt;&lt;code&gt;401&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Owner with valid token&lt;/td&gt;
&lt;td&gt;Success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Different user with valid token&lt;/td&gt;
&lt;td&gt;Rejected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User from another tenant&lt;/td&gt;
&lt;td&gt;Rejected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User with insufficient role&lt;/td&gt;
&lt;td&gt;Rejected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Viewer attempting deletion&lt;/td&gt;
&lt;td&gt;Rejected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Administrator inside allowed scope&lt;/td&gt;
&lt;td&gt;Success&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Test more than reads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create&lt;/li&gt;
&lt;li&gt;read&lt;/li&gt;
&lt;li&gt;update&lt;/li&gt;
&lt;li&gt;delete&lt;/li&gt;
&lt;li&gt;download&lt;/li&gt;
&lt;li&gt;share&lt;/li&gt;
&lt;li&gt;approve&lt;/li&gt;
&lt;li&gt;archive&lt;/li&gt;
&lt;li&gt;transfer ownership&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For multi-tenant systems, create at least two tenant contexts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tenant A user → Tenant A resource → Allowed
Tenant A user → Tenant B resource → Rejected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For nested resources, intentionally mix identifiers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Project A ID
+
Comment from Project B
=
Rejected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Applications should also decide whether unauthorized resource requests return &lt;code&gt;403&lt;/code&gt; or &lt;code&gt;404&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;403&lt;/code&gt; response confirms that the resource exists but access is forbidden.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;404&lt;/code&gt; response can avoid revealing whether a protected resource exists.&lt;/p&gt;

&lt;p&gt;The right choice depends on the API contract and threat model.&lt;/p&gt;

&lt;p&gt;What matters is that the behavior is deliberate and consistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partial Protection Is Still a Security Failure
&lt;/h2&gt;

&lt;p&gt;The shortcut did not look reckless.&lt;/p&gt;

&lt;p&gt;It looked like ordinary controller and repository code behind an authenticated route.&lt;/p&gt;

&lt;p&gt;That was why it survived.&lt;/p&gt;

&lt;p&gt;The token was valid.&lt;/p&gt;

&lt;p&gt;The current user was known.&lt;/p&gt;

&lt;p&gt;Anonymous requests were rejected.&lt;/p&gt;

&lt;p&gt;The endpoint was still unsafe because the requested resource had no enforced ownership, tenant, role, or permission boundary.&lt;/p&gt;

&lt;p&gt;The lasting fix was not a stronger token, a longer identifier, or another scattered condition.&lt;/p&gt;

&lt;p&gt;It was making authorization part of the resource-access model and testing the application with valid users who should still be denied.&lt;/p&gt;

&lt;p&gt;Security failures often survive because partial protection is mistaken for complete protection.&lt;/p&gt;

&lt;p&gt;A valid token should open the application.&lt;/p&gt;

&lt;p&gt;It should never open every record inside it.&lt;/p&gt;

&lt;p&gt;Which authorization boundary is easiest to miss in your APIs: ownership, roles, tenant isolation, or action-specific permissions?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Streaming-First UI Framework Built for the AI Era</title>
      <dc:creator>Muhammad Masood Kausar</dc:creator>
      <pubDate>Mon, 20 Jul 2026 14:04:38 +0000</pubDate>
      <link>https://dev.to/masaood/a-streaming-first-ui-framework-built-for-the-ai-era-4kpk</link>
      <guid>https://dev.to/masaood/a-streaming-first-ui-framework-built-for-the-ai-era-4kpk</guid>
      <description>&lt;p&gt;Most AI products still stream words.&lt;/p&gt;

&lt;p&gt;But what if an AI model could stream the interface itself?&lt;/p&gt;

&lt;p&gt;I recently explored &lt;strong&gt;Aktion&lt;/strong&gt;, an ambitious open-source project created by my mentor, &lt;strong&gt;Asfandiyar Khan&lt;/strong&gt;, a senior frontend engineer based in Germany.&lt;/p&gt;

&lt;p&gt;Aktion is a streaming-first UI framework designed to turn compact, JavaScript-shaped instructions into reactive and interactive user interfaces.&lt;/p&gt;

&lt;p&gt;Instead of producing another Markdown response or a large block of frontend code, an AI model can progressively generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cards&lt;/li&gt;
&lt;li&gt;Charts&lt;/li&gt;
&lt;li&gt;Forms&lt;/li&gt;
&lt;li&gt;Tables&lt;/li&gt;
&lt;li&gt;Dashboards&lt;/li&gt;
&lt;li&gt;Navigation&lt;/li&gt;
&lt;li&gt;Interactive workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What makes Aktion different?
&lt;/h2&gt;

&lt;p&gt;Traditional AI-generated frontend code often requires the model to coordinate several independent systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Framework syntax&lt;/li&gt;
&lt;li&gt;Package imports&lt;/li&gt;
&lt;li&gt;State management&lt;/li&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;li&gt;Form handling&lt;/li&gt;
&lt;li&gt;Styling&lt;/li&gt;
&lt;li&gt;Data fetching&lt;/li&gt;
&lt;li&gt;Component libraries&lt;/li&gt;
&lt;li&gt;Dependency versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aktion takes a different approach.&lt;/p&gt;

&lt;p&gt;It gives developers and AI agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A compact JavaScript-shaped reactive language&lt;/li&gt;
&lt;li&gt;A unified UI runtime&lt;/li&gt;
&lt;li&gt;A consistent component vocabulary&lt;/li&gt;
&lt;li&gt;Built-in application capabilities&lt;/li&gt;
&lt;li&gt;A framework-agnostic Web Component&lt;/li&gt;
&lt;li&gt;Streaming support for progressively generated interfaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The central integration point is the &lt;code&gt;&amp;lt;aktion-app&amp;gt;&lt;/code&gt; Web Component.&lt;/p&gt;

&lt;p&gt;Because of this approach, Aktion can be embedded inside React, Vue, Angular, Svelte, plain HTML, or another host environment without rebuilding the generated UI layer for every framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why streaming-first UI matters
&lt;/h2&gt;

&lt;p&gt;Most AI interfaces wait until a response is complete before presenting the final output.&lt;/p&gt;

&lt;p&gt;Aktion is designed so completed statements can be rendered while the model is still generating the rest of the response.&lt;/p&gt;

&lt;p&gt;A heading can appear first.&lt;/p&gt;

&lt;p&gt;Then a chart.&lt;/p&gt;

&lt;p&gt;Then filters, forms, cards, and interactive controls.&lt;/p&gt;

&lt;p&gt;The AI response does not only describe an application.&lt;/p&gt;

&lt;p&gt;It gradually becomes the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  A smaller target for AI-generated interfaces
&lt;/h2&gt;

&lt;p&gt;One of Aktion’s most interesting ideas is its constrained language.&lt;/p&gt;

&lt;p&gt;AI models normally have enormous freedom when generating frontend applications. They must choose libraries, understand different APIs, manage imports, and connect tools that were not necessarily designed to work together.&lt;/p&gt;

&lt;p&gt;More freedom can also create more incompatible decisions.&lt;/p&gt;

&lt;p&gt;Aktion reduces that decision space by providing one language, one runtime, and one predictable set of interface primitives.&lt;/p&gt;

&lt;p&gt;The important idea is not only that Aktion contains many features.&lt;/p&gt;

&lt;p&gt;It is that AI-generated interfaces may become more dependable when models generate into a smaller and more controlled environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  More than a component library
&lt;/h2&gt;

&lt;p&gt;Aktion brings several common frontend concerns into one system, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reactive state&lt;/li&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;li&gt;Forms&lt;/li&gt;
&lt;li&gt;Data fetching&lt;/li&gt;
&lt;li&gt;Themes&lt;/li&gt;
&lt;li&gt;Responsive styling&lt;/li&gt;
&lt;li&gt;Charts&lt;/li&gt;
&lt;li&gt;Realtime interfaces&lt;/li&gt;
&lt;li&gt;Internationalization&lt;/li&gt;
&lt;li&gt;Testing utilities&lt;/li&gt;
&lt;li&gt;Server-side rendering&lt;/li&gt;
&lt;li&gt;A large built-in component vocabulary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This does not automatically make it the right solution for every application.&lt;/p&gt;

&lt;p&gt;However, it makes Aktion an interesting experiment in how frontend runtimes could evolve for generative UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  The engineering effort behind Aktion
&lt;/h2&gt;

&lt;p&gt;Building a framework is very different from building a small library.&lt;/p&gt;

&lt;p&gt;Aktion brings together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A language&lt;/li&gt;
&lt;li&gt;A parser&lt;/li&gt;
&lt;li&gt;A reactive runtime&lt;/li&gt;
&lt;li&gt;A rendering system&lt;/li&gt;
&lt;li&gt;A component vocabulary&lt;/li&gt;
&lt;li&gt;Streaming behavior&lt;/li&gt;
&lt;li&gt;Developer tooling&lt;/li&gt;
&lt;li&gt;LLM integration&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;Interactive demonstrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is inspiring to see my mentor transform years of frontend experience into such an ambitious open-source project.&lt;/p&gt;

&lt;h2&gt;
  
  
  An idea worth exploring
&lt;/h2&gt;

&lt;p&gt;Aktion may still be an early project, and questions around security, runtime size, extensibility, debugging, and long-term stability deserve careful discussion.&lt;/p&gt;

&lt;p&gt;But the architectural question behind it is important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should AI continue generating unrestricted frontend applications, or should we design smaller runtimes that give models a clearer and more predictable target?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The future of generative UI may not depend only on making AI models more capable.&lt;/p&gt;

&lt;p&gt;It may also depend on designing better environments for them to generate into.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explore the project
&lt;/h2&gt;

&lt;p&gt;🌐 &lt;a href="https://asfand-dev.github.io/aktion/index.html" rel="noopener noreferrer"&gt;Visit the Aktion project homepage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;a href="https://github.com/asfand-dev/aktion" rel="noopener noreferrer"&gt;View Aktion on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📖 &lt;a href="https://medium.com/skillstuff/inside-aktion-a-streaming-first-ui-framework-built-for-the-ai-era-37630984c876" rel="noopener noreferrer"&gt;Read my complete article on Medium&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations to &lt;strong&gt;Asfandiyar Khan&lt;/strong&gt; on this impressive engineering effort and valuable contribution to the open-source community.&lt;/p&gt;

&lt;p&gt;What are your thoughts on streaming-first generative UI?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
