# Authorization: Who Can Do What

After authentication, backend systems feel… calmer.

You know who the user is. You trust their identity. Requests stop failing randomly.

And then a new question appears. “Okay, but what is this user allowed to do?”

That question is **authorization**. And if there’s one mistake backend engineers make repeatedly, it’s this: Treating authorization as a continuation of authentication.

It isn’t. They solve very different problems.

## A Simple Sentence That Clears Everything Up

Let’s lock this in early:

* **Authentication** answers: *Who are you?*
    
* **Authorization** answers: *What are you allowed to do?*
    

Same request. Different concern. When these get mixed, systems become fragile, insecure, and hard to reason about.

### Why Auth Feels Like It Should Handle Authorization

At first, it feels logical to bundle authorization into authentication. When a user logs in, you already know: Who they are, Maybe what role they have, Maybe some claims like `isAdmin`.

So it’s tempting to think: “If the token already knows this, why not decide permissions there?”

But this is where systems quietly drift into trouble. Consider these two facts:

* **Identity answers “who”**
    
* **Authorization answers “can you do this, here, right now?”**
    

Those are very different questions. A user can be:

* Authenticated ✔️
    
* But not allowed to edit *this* document
    
* Or allowed today, but not tomorrow
    
* Or allowed on one resource, but not another
    

Identity is stable. Permissions are situational. This is why authentication *cannot* safely decide authorization on its own.

### Identity Is Relatively Static

A user: Logs in, Has an ID, Has an email, Has an account. These things don’t change often. Authentication answers this once per request and moves on.

That stability makes auth predictable.

## Permissions Are Contextual and Fluid

Authorization depends on: The resource being accessed, The action being performed, The current state of the system, Sometimes even time.

The same user can: Read one resource, Modify another, Be blocked from a third.

Authorization lives in **context**, not identity.

## A Quick Real-World Analogy

You enter an office building. Security checks your ID. That’s authentication.

Then: You can access some floors, You’re blocked from others, You need approval for certain rooms.

That’s authorization. Same person. Different permissions.

## Why Mixing Them Causes Trouble

When auth and authorization are tangled together: Tokens grow huge, Logic spreads everywhere, Changes require reissuing tokens, Security bugs hide in assumptions.

You start encoding business rules into identity. That never ages well.

### Where Authorization Should Actually Live

Authorization should live: Close to the resource, Close to the decision, Close to the business logic.

Not inside the authentication mechanism. Authentication proves identity. Authorization interprets that identity **in context**.

## Role-Based Authorization (The Simplest Model)

Roles are often the first authorization model teams adopt. It usually begins simply: `admin`, `editor`, `viewer` .

Rules feel clean: Admins can do everything, Editors can modify content, Viewers can only read.

This works… until reality shows up. Now imagine a growing system:

* Some editors can only edit **their own** content
    
* Some admins can manage users but not billing
    
* Some users can approve changes **only during business hours**
    
* Some permissions are temporary
    
* Some permissions are resource-specific
    

What happens next? Roles multiply: `admin`, `super-admin`, `content-admin`, `billing-admin`, `editor`, `senior-editor`, `external-editor`.

Soon, roles stop being meaningful descriptions and start becoming **permission bundles with unclear boundaries**. At that point: Adding a role becomes risky, Removing one breaks things, No one is sure what a role actually allows.

This is why roles don’t scale well on their own.

## Why Roles Don’t Scale Forever

Roles assume: Few user types, Simple rules, Stable permissions. Real systems are messier.

Questions start appearing:

* Can this user edit *this* resource?
    
* What about resources they created?
    
* What about temporary permissions?
    
* What about shared ownership?
    

Roles alone can’t answer these cleanly.

### Permission-Based Thinking

Instead of asking: “What role does this user have?”

Ask: “Does this user have permission to perform this action on this resource?”

This shifts thinking from identity to intent. Authorization becomes a **decision**, not a label.

### Resource-Centric Authorization

This is the mental upgrade. Authorization checks usually look like:

* Who is the user?
    
* What resource is being accessed?
    
* What operation is requested?
    

The answer depends on all three. This is why authorization logic belongs near handlers and services, not auth middleware.

### Why Authorization Happens on Every Request

*(And Why That’s Still Okay)*

Authorization decisions must be evaluated every time because:

* Resource ownership can change
    
* Permissions can be revoked
    
* Context can differ per request
    
* System state can evolve
    

That sounds expensive. And yes, it *can* be. But systems don’t handle this by skipping authorization. They handle it by **optimizing how it’s checked**.

Common strategies include:

* Keeping authorization logic close to the data
    
* Using indexed lookups instead of complex joins
    
* Caching coarse permissions carefully
    
* Avoiding embedding fine-grained rules in tokens
    

The important thing is this: You optimize authorization checks — you don’t eliminate them.

Skipping authorization for performance is how subtle security bugs appear.

### Tokens Should Carry Identity, Not Decisions

This is a critical boundary. Good tokens contain: User ID, Basic claims, Maybe coarse roles.

Bad tokens contain: Fine-grained permissions, Resource-specific access, Business rules.

Why? Because permissions change faster than tokens expire.

### Authorization Is a Business Problem, Not a Protocol Problem

HTTP doesn’t help you here. There’s no header for: “Is this user allowed to do this?”

That’s intentional. Authorization is deeply tied to: Product rules, Business logic, Domain concepts.

Trying to “standardize” it too early usually backfires.

## The One Mental Model to Keep

Let’s tie everything together.

* **Authentication** proves identity
    
* **Authorization** evaluates intent in context
    
* **Identity is stable**
    
* **Permissions are fluid**
    

Authentication answers *who you are*. Authorization decides *what you can do, here and now*. When these concerns stay separate: Security stays predictable, Business rules stay readable, Systems evolve safely.

When they’re mixed: Tokens grow heavy, Logic spreads everywhere, Changes become dangerous.

The web works not because it hides complexity, but because it **keeps responsibilities cleanly separated**.

## What Comes Next

Now that we know: Who the user is, What they’re allowed to do.

The next hard question is: “How do we protect systems from misuse, abuse, and overload?”

That’s where rate limiting and trust come in.

➡️ **Next article:**  
[**Rate Limiting, Abuse, and Trust at Scale**](https://thinking-in-backend.hashnode.dev/rate-limiting-abuse-and-trust-at-scale)

This article is part of the [**Thinking in Backend**](https://thinking-in-backend.hashnode.dev/) series, where we learn backend engineering by focusing on how systems think, not just how code runs.
