SECURITY FEATURE
Protected Route
Add one attribute to any route and the framework enforces access — 403 returned automatically.
Feature Guide
A quick orientation block that answers the essential questions: what this feature does, how it works, why it matters, and the key concepts behind it.
What this does
Add one access attribute and one optional permission attribute and the framework enforces access — 401 for unauthenticated requests, 403 for unauthorized ones.
Route Guards
Access is enforced before the handler runs
The guard chain decides whether the request should proceed, fail with 401/403, or bypass checks entirely for public endpoints.
// Protected: only admin can access
#[RequiresPermission('users.manage')]
#[AsPayload(path: '/admin/users', methods: ['GET'])]
class UserListPayload { ... }
// Public: no auth required
#[PublicEndpoint]
#[AsPayload(path: '/demo/routing/basic', methods: ['GET'])]
class BasicRoutePayload { ... }
| Scenario | Result |
|---|---|
| Authenticated + correct permission | 200 OK |
| Authenticated + missing permission | 403 Forbidden |
| Not authenticated | 401 Unauthorized |
#[PublicEndpoint]
|
200 OK (no auth check) |
Verified against Semitexa Ultimate 2026.09.19.1020
Protected Route
Mark a payload with #[AsProtectedPayload] and the framework enforces access — 401 for unauthenticated requests, 403 for authenticated subjects without the required permission.
How it works
The guard chain runs before the handler for every protected payload. #[RequiresPermission] on the payload declares the required permission slug; #[RequiresCapability] declares a coarse-grained capability gate. The chain evaluates the resolved principal against the declared grants and either allows the request through, returns 401 for unauthenticated subjects, or returns 403 for authenticated subjects without the required grant. #[AsPublicPayload] is the explicit opt-out for anonymous routes.
Why this matters
Access control declared on the payload is reviewable and enforced uniformly. There is no handler code that checks permissions manually, no way to forget the check in one handler but not another, and no logic duplication when two handlers share the same protection rule. Because the access attribute and the permission/capability attributes co-exist on the same class, a code reviewer sees both the security stance (public / protected / service) and the fine-grained guards in one read.