Engineering reference · 03

The browser can suggest.
Only the server can grant.

The UI uses the current caller’s permissions to remove unavailable actions. The server independently resolves that caller and rechecks the generated key inside the handler. Changing HTML, JavaScript, or a request cannot manufacture authority.

Generated catalogCurrent caller onlyHandler enforcement
DepartmentCreateCommand.g.csServer boundary
var permissions = await permissionService
    .GetPermissionSetAsync(ct);

if (!permissions.IsGranted(
        DepartmentPermissions.Create))
{
    return CxResult<DepartmentId>.Failure(
        new CxError("forbidden",
                    "Not authorized."));
}
Keyentities.department.create
00 · FIVE LINK CHAIN

A permission is only real when every link exists.

Generated declarations remove naming drift. Catalog and grants make the key manageable. The handler is the load-bearing security link; client gates communicate the same decision to the user.

Permission flow from generated key through catalog, grant resolution, server handler enforcement, and client gating, including rejection of a forged browser permission.
Permission enforcementChanging browser state cannot change the server-resolved caller.
01

Generate key

{module}.{entity}.{verb} comes from the business surface.

02

Publish catalog

Known permissions are seeded and available to administration.

03

Grant access

Roles, job titles, and user overrides form the effective set.

04

Enforce handler

The server resolves the current authenticated caller and checks immediately before work.

05

Gate the UI

Buttons and pages reflect access without pretending to be the boundary.

01 · GENERATED CATALOG

Keys are code, not scattered strings.

CRUD permissions are emitted alongside the entity contract. Custom commands and queries can add their own keys through the same generation path.

One vocabulary everywhere

Catalog boot, administration, server handlers, AI tool descriptors, pages, and components refer to the same constants.

  • Renames and generator defects become visible diffs.
  • Typos cannot quietly create a second permission.
  • Public operations remain an explicit decision.
  • AI-discoverable records inherit View protection.
Framework/Department/DepartmentPermissions.g.csGENERATED
public static class DepartmentPermissions
{
    public const string View =
        "entities.department.view";
    public const string Create =
        "entities.department.create";
    public const string Update =
        "entities.department.update";
    public const string Delete =
        "entities.department.delete";
}
02 · CLIENT EXPERIENCE

The client fetches its own effective set.

The permission endpoint accepts no user identifier. It answers only for the authenticated caller. Until the set is loaded, permission gates fail closed.

Client permission source · conceptual excerptCALLER-BOUND
var keys = await http.GetFromJsonAsync<string[]>(
    "api/security/my-permissions", ct);

// No userId can be supplied by the browser.
permissionCache.ReplaceWith(keys ?? []);
DepartmentsGrid.razorUX GATE
<CweEntityGrid
  Operations="Departments"
  CreatePermission="@DepartmentPermissions.Create"
  EditPermission="@DepartmentPermissions.Update"
  DeletePermission="@DepartmentPermissions.Delete" />

<CxPermissionGate
  Permission="@DepartmentPermissions.View">
  ...authorized page content...
</CxPermissionGate>
Important

Client gating prevents confusion and unnecessary requests. It is never cited as proof of authorization; the server still decides.

03 · HOSTILE CLIENT

Assume the browser is controlled by an attacker.

Every client-side artifact is inspectable and mutable. Security holds because the browser carries a request—not the authority to approve it.

AttemptWhat the attacker changesServer outcome
Reveal a hidden buttonDOM or CSS makes Create visible.The create handler resolves the caller and denies the missing key.
Forge local permission stateJavaScript cache claims entities.department.create.Local state is never accepted as a grant; the server uses its own effective set.
Call the API manuallyA crafted POST bypasses the page.The authenticated route and handler check still execute.
Tamper with an identifierThe request targets another record or scope.Application-state and relationship checks run on server-loaded data.
Reuse stale UIA grant is revoked after the page loaded.The live handler resolution sees the revoked permission and denies the operation.
Invoke AI indirectlyThe assistant is asked to perform an unavailable mutation.The tool is filtered by permission and the downstream handler rechecks.
04 · DEFENSE IN DEPTH

One handler check is essential. It is not alone.

Independent layers limit mistakes and normalize failure while preserving the handler as the decisive authorization boundary.

Transport

Authenticated endpoint groups

Anonymous requests do not enter protected entity operations.

Application

Handler permission checks

Every operation checks the live effective set close to the business action.

Persistence

Save pipeline safeguards

Validation, authorization, and audit behavior are protected from shortcut writes.

Composition

Analyzer enforcement

Raw calls and unsafe placements become diagnostics during development.

AI

Permission-aware registry

Runtime tools cannot exceed page reachability or caller access.

Startup

Catalog boot guard

Known generated permissions and grants reconcile into one managed vocabulary.

Effective set

Access is resolved as set algebra across roles, job titles, and explicit user adjustments for the authenticated caller. Administrator behavior is deliberate—not a client flag.

Next engineering page

See how one language entry becomes a complete translation catalog.

Open localization →