Authorization Boundaries
Requires access checks at trusted boundaries and tests that protect resources from unauthorized users.
Scenario
You maintain a multi-user SaaS application.
Authentication answers:
Who is making this request?
Authorization answers:
Is this user allowed to perform this action?
The application contains organizations, projects, and resources owned by different users.
You want coding agents to preserve authorization checks whenever new operations are introduced.
Repository Structure
saas-api/
├── src/
│ ├── auth/
│ ├── authorization/
│ │ ├── permissions.ts
│ │ └── policies.ts
│ ├── projects/
│ ├── organizations/
│ └── routes/
├── tests/
│ └── authorization/
└── AGENTS.md
AGENTS.md
# Project Instructions
## Authorization
- Authentication alone does not grant access to application resources.
- Use the existing authorization policies or permission helpers before protected operations.
- Check authorization against the resource being accessed when ownership or membership matters.
- Do not duplicate authorization logic inside individual routes when an existing policy covers the operation.
## Resource Access
- Do not trust resource ownership or organization IDs supplied by the client without server-side authorization.
- Scope data access according to the authenticated user's permitted organizations or resources.
- Preserve existing tenant boundaries.
## Privileged Operations
- Keep administrative operations behind the existing administrative authorization checks.
- Do not infer administrative access from UI visibility or client-provided roles.
## Testing
For authorization changes, test:
- an allowed user;
- an authenticated but unauthorized user;
- an unauthenticated request where applicable;
- cross-tenant access when tenant isolation is involved.
What This Does
This distinguishes authentication from authorization.
A request can be:
authenticated ✓
authorized ✗
For example, user A may be correctly signed in but still should not access:
User B's private project
The application therefore needs both:
identity
+
permission
before performing the operation.
What This Does NOT Do
The file does not assume that hiding a button in the frontend provides authorization.
For example:
{user.isAdmin && <DeleteOrganizationButton />}
may improve the UI, but it does not protect the backend operation.
A user can still construct an HTTP request directly.
Authorization must be enforced at the trusted application boundary.
The instructions also do not require every feature to invent its own role checks.
Existing policies should be reused.
Why These Instructions Matter
Consider:
GET /projects/:projectId
The route receives:
projectId = 123
The application finds project 123 and returns it.
Authentication was checked.
But if project 123 belongs to another organization, the application may have created an insecure direct object reference.
The correct flow is closer to:
Authenticate user
↓
Load or identify resource
↓
Check permission
↓
Return resource
Tenant boundaries deserve particular attention.
A query such as:
SELECT * FROM projects WHERE id = $1
may be insufficient if access must also be constrained by organization membership.
Key Decisions
Authentication is not authorization
Knowing who the user is does not automatically answer what they may access.
Authorize server-side
Frontend state can improve user experience.
It is not a security boundary.
Protect resource ownership
Identifiers supplied by clients should not be treated as proof of access.
Test denial paths
A permission system that works for allowed users but accidentally permits cross-tenant access is still broken.
Reuse policies
Central authorization rules are easier to review and maintain than dozens of slightly different inline checks.
When to Use This Pattern
Use this pattern when:
- multiple users access private resources;
- organizations or tenants exist;
- roles or permissions control behavior;
- administrative operations exist;
- resource ownership matters.
Authorization guidance is especially important in multi-tenant applications where one missing check can expose another customer's data.