← Routing & Handlers

ROUTING & HANDLERS FEATURE

Public Payload

Anonymous access is never accidental: a payload is public only when it says #[AsPublicPayload].

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

Semitexa is closed by default: every payload picks one of #[AsPublicPayload], #[AsProtectedPayload] or #[AsServicePayload], and anonymous access is the explicit #[AsPublicPayload] opt-in.

How it works

The access policy resolver inspects the payload's access attribute at boot. #[AsPublicPayload] marks the route as anonymous-allowed; #[AsProtectedPayload] and #[AsServicePayload] return 401 to a guest before the handler runs. A payload that declares none of the three is never routed.

Why it matters

This flips the usual risk profile. Teams do not have to remember to secure every endpoint one by one. The safe default is built in, and public exposure becomes a deliberate code review event.

Key concepts

#[AsPublicPayload]
Marks a payload as explicitly reachable without authentication.
#[AsProtectedPayload]
Requires a signed-in user; a guest gets 401 before the handler runs.
401 Unauthorized
The framework response returned when a guest hits a protected endpoint.
Authorizer
Core service that decides whether the current subject may access the resolved payload.

Security Default

Private unless you say otherwise

A payload that declares no access attribute is never routed, so public access is always deliberate and visible in code.

// Signed-in users only
#[AsProtectedPayload(path: '/dashboard', methods: ['GET'])]
class DashboardPayload {}

// Explicitly public
#[AsPublicPayload(path: '/catalog', methods: ['GET'])]
class CatalogPayload {}
Route declaration Guest request result
#[AsPublicPayload] 200 OK
#[AsProtectedPayload] 401 Unauthorized
#[AsServicePayload] 401 Unauthorized
#[AsPublicPayload] + #[RequiresPermission] Refused on its first request
No access attribute Not routed
#[AsPublicPayload] #[AsProtectedPayload] #[AsServicePayload] 401 Unauthorized Authorizer

Verified against Semitexa Ultimate 2026.09.19.1020

Public Payload

Semitexa is closed by default. Every payload picks one of three access attributes — #[AsPublicPayload], #[AsProtectedPayload], or #[AsServicePayload] — and the framework refuses to discover a payload that declares none. Anonymous access is the explicit #[AsPublicPayload] opt-in, never an implicit fallback.

How it works

The access policy resolver inspects the payload's access attribute at boot. #[AsPublicPayload] marks the route as anonymous-allowed. #[AsProtectedPayload] requires a User-domain principal and returns 401 to guest requests before the handler runs. #[AsServicePayload] requires a Service-domain principal (a verified webhook signature, machine token, or partner credential) and similarly returns 401 on missing or wrong-domain credentials.

Why this matters

The three attributes are mutually exclusive and explicit. Public exposure becomes a deliberate code-review event because the keyword AsPublicPayload appears at the type. There is no "default protected" fallback that someone could remove; there is no shared base attribute that could accidentally drop a route into the wrong access class. A payload that declares none of the three never reaches the route registry, so a missing attribute is a build-time discovery failure rather than a silently exposed endpoint.

See also

© Jeff Sickel: "Deleted code is debugged code."

Public Payload Trusted input boundary
<?phpdeclare(strict_types=1);namespace App\Payload\Routing;use Semitexa\Core\Attribute\AsPublicPayload;use App\Resource\CatalogPageResource;#[AsPublicPayload(    responseWith: CatalogPageResource::class,    path: '/catalog',    methods: ['GET'],)]final class PublicCatalogPayload{}

How it works

The access policy resolver inspects the payload's access attribute at boot. #[AsPublicPayload] marks the route as anonymous-allowed; #[AsProtectedPayload] and #[AsServicePayload] return 401 to a guest before the handler runs. A payload that declares none of the three is never routed.

Why it matters

This flips the usual risk profile. Teams do not have to remember to secure every endpoint one by one. The safe default is built in, and public exposure becomes a deliberate code review event.

Key concepts

#[AsPublicPayload]
Marks a payload as explicitly reachable without authentication.
#[AsProtectedPayload]
Requires a signed-in user; a guest gets 401 before the handler runs.
401 Unauthorized
The framework response returned when a guest hits a protected endpoint.
Authorizer
Core service that decides whether the current subject may access the resolved payload.

Support Semitexa
Built for developers who prefer control over magic. Your support helps keep it fast, open, and evolving.

Donate via PayPal