KemalIdentity::Authz::DenialReason
Inherits Enum < Comparable < Value < Object
Why an authorization check said no.
For the audit log, not for the response. The same discipline as FailureReason, and
for a sharper reason here: NotAMember and NotPermitted tell an attacker whether the
tenant they just guessed at exists and whether they are inside it. Every denial renders one
identical 403 — ErrorHandler does not read this, and neither should a route.
Constants
Nobody granted it. The ordinary case, and the one that should be boring.
The check named a tenant this principal does not belong to. Distinct from NotPermitted
because it means something different to whoever reads the trail: a member without a role
is a provisioning gap, and a non-member reaching for a tenant's data is an incident.
The principal is bound to one tenant and the check named another. This is the horizontal privilege-escalation attempt — the id in the URL swapped for somebody else's — and it is refused before membership is even consulted.
A role grants this permission and the caller holds that role, but they have not proved who they are strongly enough for this particular action. The application should prompt for a second factor rather than show a dead end.
The permission was never declared. Fails closed, and is named separately because it is almost always a typo or a half-finished rename rather than an access-control event.
The account holds the permission, but the credential presenting the request does not.
A personal access token scoped to reports:read used against releases:write. The
account's grant is not in question; the token's attenuation is
(blueprints/0021-credential-reference.md).
An application authorizer's own reason, named by Forbidden#code.
Five members cannot describe every policy — a closed change window, an unmanaged device,
an incident lockdown — and an authorizer forced to report NotPermitted for those loses
the only thing the audit trail wanted.