class

KemalIdentity::Authz::Authorizer

Inherits Reference < Object

Decides whether a principal may perform an action.

Why this is not part of authentication

docs/06-roadmap.md puts authorization last on purpose. Authentication answers "who is this", authorization answers "and may they", and the two have different lifetimes: a session is minted once and lives for days, while a grant can be taken away in the middle of it. Baking the second into the first is what produces an application where firing somebody takes effect when their session happens to expire.

Which is the reason Principal carries no roles and no permissions, and why nothing here writes any into a session or a token. Every check reads the current answer — from the store, or from a cache measured in seconds and documented as such.

Implementing it directly

RBAC is the implementation this shard ships, and it is deliberately opinionated: roles in code, assignments in the database, no wildcards. An application whose authorization model is genuinely different — attribute-based rules, per-record ownership, roles administered at runtime — subclasses this instead and keeps everything else. That is the whole reason authorization is a contract rather than a table.

Instance methods

can?(principal : Principal, permission : String, context : Context) : Bool

The yes or no, for a call site that does not need the reason — a template deciding whether to render a button.

Source
can?(principal : Principal, permission : String, tenant_id : String | Nil = nil) : Bool

The yes or no, for a call site that does not need the reason — a template deciding whether to render a button.

Source
decide(principal : Principal, permission : String, context : Context) : Decision

The decision, with the reason or the granting role attached.

context carries the tenant, the resource being acted on, environment attributes and the credential that proved the request. A Context rather than a longer parameter list because this method is frozen at v1.0: the last time it needed something new — a resource — there was nowhere to put it, and an application implementing ownership rules had to bypass env.auth and lose the audit line, the step-up mapping and the uniform 403 along with it (blueprints/0022-authorization-context-and-denials.md).

context.tenant_id nil asks the question outside any tenant. That is not "any tenant": a permission held only inside tenant A is not granted by a check that names no tenant, and a route that forgets to pass the tenant it is operating on gets a denial rather than a quiet upgrade to global scope.

Source
decide(principal : Principal, permission : String, tenant_id : String | Nil = nil) : Decision

The tenant-only form, kept because it is what most call sites want and what every implementation before v0.8 was written against.

Source