Security & Server ActionseQuantic.UI facilitates communication between the client and the server through Server Actions, while ensuring that this bridge is secure by default.
A Server Action is a C# method defined in a component that can be invoked directly from the browser. The compiler automatically generates the call bridge (Fetch API) and the server middleware resolves the execution.
[Authorize(Roles = "Admin")]
public async Task<bool> DeleteUser(Guid userId) {
// Logic executed only on the server
🔒 A page that requires authorization
Since 0.2.0-preview.61
[Page("/backoffice/queue")]
[Authorize(Policy = "Backoffice")]
public sealed class VerificationQueuePage : StatefulComponent, IServerPrefetch { … }
The same [Authorize] and [AllowAnonymous] a Server Action takes guard a page. Its route carries them as endpoint metadata, as RequireAuthorization would, so ASP.NET Core's authorization decides with the schemes and policies the app configured (AddAuthentication, AddAuthorization):
•
an anonymous full load is challenged by the default scheme, the OpenID Connect redirect to sign in, for example;
•
a signed-in visitor without the policy gets 403;
•
a client navigation into the page gets a 401 or a 403 instead of the page, and the router then loads the route in full, so the challenge or the 403 happens as it would on any visit;
•
a refused request never reaches the page: its IServerPrefetch does not run, and none of its fields are written into the HTML.
[Authorize] with no policy asks only for a signed-in visitor. Under an app-wide FallbackPolicy, a page marked [AllowAnonymous] (the sign-in page) still serves, and so do the runtime and the page modules it needs. A class-level [Authorize] used to guard only the page's Server Actions; it guards the page now too.
The 404 and 500 pages an app registers are asked the same question before they are drawn in place of a route, as their own routes ask it: a page that names no requirement is under the FallbackPolicy, the request is the policy's resource, and a page the visitor may not see is not drawn, nor does its IServerPrefetch run.
eQuantic.UI supports [Authorize] and [AllowAnonymous] attributes.
•
The ServerActionsMiddleware checks if the current user has the necessary permissions before invoking the method.
•
If authorization fails, the server returns a 403 Forbidden or 401 Unauthorized error, blocking the execution of the business logic.
To prevent injection attacks and excess resource consumption:
•
Size Limit: The middleware imposes strict limits on the size of the request body.
•
Type Whitelist: Argument deserialization is restricted to known and secure types, preventing insecure deserialization attacks.
Only methods explicitly marked with [ServerAction] can be invoked. It is not possible to call any arbitrary public method via API, ensuring that the attack surface is controlled.
4. Where the Request Came From
Since 0.2.0-preview.61
A Server Action refuses a request that another site's page sends, before anything of it is read. The browser says where a request came from, and the endpoint answers 403 Forbidden when:
•
the Origin is neither the app's own host nor an origin the app allows, the opaque Origin: null included;
•
there is no Origin, and Sec-Fetch-Site says cross-site or same-site.
A request with neither header is not a browser's, and runs. The app's own host is the request's Host: behind a proxy that rewrites it, app.UseForwardedHeaders() restores it from the proxies the app trusts, and a raw X-Forwarded-Host is never read. The host and the port are compared, not the scheme, and a Host without a port stands for the origin's default one, so an app behind a proxy that ends TLS needs no setting.
A page served from another domain than its actions lists that origin, in appsettings.json:
"AllowedOrigins": [ "https://admin.example.com" ]
or in Program.cs:
builder.Services.AddUI(options => options.AllowServerActionOrigins("https://admin.example.com"));
Each origin is scheme://host[:port], with no path or query. One that is not stops the app at start, naming the value.
Communication is done via HTTP POST to the reserved endpoint /api/_equantic/actions.
•
Payload: Contains the unique Action ID and the list of serialized arguments.
•
Response: Returns the result object or a structured error.