When building on AWS, it's natural to look at IAM as a possible foundation for authorization. It's expressive, and central to how access is controlled across the platform. At some point, many teams ask a reasonable question: can this also be used to manage permissions inside an application?
That question is worth asking - not because IAM is the wrong tool, but because it reveals an important boundary. IAM and application authorization solve related problems, but they operate at very different layers of a system. Understanding that boundary early tends to make everything downstream easier.
What IAM is designed to do
IAM exists to answer a very specific kind of question:
Can this principal perform this action on this AWS resource?
That scope is intentional. IAM governs access to AWS itself - APIs, services, resources, and identities at the infrastructure level. Its policy model reflects that focus, and it excels at it.
Used as intended, IAM is very good at:
- controlling service-to-service access
- enforcing least privilege
- protecting infrastructure boundaries
- expressing trust relationships
- evaluating policies at massive scale
In short, IAM is foundational infrastructure security. The confusion starts when we expect it to describe application behavior.
Where application authorization diverges
Application authorization tends to ask a different class of questions:
Can this user edit this record?
Does access depend on which organization or location they're acting in?
Is permission temporary, delegated, or conditional?
Does the decision depend on runtime data or relationships?
These aren't infrastructure concerns - they're domain concerns.
They change frequently. They evolve as features evolve. They depend on business meaning rather than on resource identity. And they often involve concepts that don't map cleanly to cloud resources at all.
Trying to force those ideas directly into IAM policies usually leads to awkward abstractions and brittle designs. Not because IAM is limited, but because it was never meant to carry that responsibility.
A useful boundary
A helpful way to think about this is to draw a clean line between two layers: Infrastructure authorization answers:
"Is this caller allowed to interact with this cloud resource?"
Application authorization answers:
"Is this actor allowed to perform this action, in this context, on this domain object?"
They sound similar, but they evolve very differently.
Infrastructure permissions tend to be relatively stable and coarse-grained. They change when infrastructure changes. Application rules, by contrast, evolve constantly as features grow, workflows change, and edge cases accumulate. They depend on context, relationships, and business meaning rather than on resource identity alone.
When these two concerns are treated as the same problem, one of them usually gets distorted. Either infrastructure policies start encoding application logic, or application code becomes cluttered with authorization checks that are hard to reason about and harder to change.
This separation is part of why AWS eventually introduced Amazon Verified Permissions. It wasn't meant to replace IAM, but to address a different layer of the problem: expressing and evaluating authorization decisions that depend on application context rather than infrastructure identity.
Seen this way, the goal isn't to choose between tools. It's to recognize that authorization has structure - and that different layers of a system are responsible for different parts of it.
IAM is foundational and indispensable. But it solves a different problem than application authorization.
Understanding where that boundary lies - and why it exists - is often the first step toward building systems that remain understandable, adaptable, and resilient as they grow.