Table of Contents

Class Actor

Namespace
Trellis.Authorization
Assembly
Trellis.Authorization.dll

Represents the current authenticated user making the request. Contains identity, permissions, forbidden permissions, and contextual attributes used by authorization behaviors.

public sealed class Actor : IEquatable<Actor>
Inheritance
Actor
Implements
Inherited Members
Extension Methods

Remarks

Hydrated during authentication/middleware. Permissions should be pre-flattened from all sources (JWT roles, database groups, organizational hierarchies) before constructing the Actor so that all permission checks remain O(1).

Scoped permissions use the "Permission:Scope" convention (e.g., "Document.Edit:Tenant_A"). Add scoped entries to Permissions and check with HasPermission(string, string).

All permission and attribute lookups use ordinal (case-sensitive) comparison. Ensure consistent casing when hydrating permissions, forbidden permissions, and attributes.

Equality is identity-based. Actor is conceptually an entity — its Id is a stable, externally-meaningful principal identifier (e.g. JWT sub claim) and the other properties are point-in-time state about that principal (granted permissions and ABAC attributes change over time). Two Actor instances with the same Id are equal even when their Permissions or Attributes differ; two with different Ids are never equal. This deliberately mirrors the framework's domain-layer Trellis.Entity<TId> semantics without taking on the full IAggregate surface (Actor is an authorization-layer principal, not a domain aggregate root).

Constructors

Actor(string, IReadOnlySet<string>, IReadOnlySet<string>, IReadOnlyDictionary<string, string>)

Convenience constructor that accepts the actor id as a raw string (typically a claim value at the authentication boundary) and wraps it in ActorId. Authors writing typed application code should prefer the Actor(ActorId, IReadOnlySet<string>, IReadOnlySet<string>, IReadOnlyDictionary<string, string>) overload.

public Actor(string id, IReadOnlySet<string> permissions, IReadOnlySet<string> forbiddenPermissions, IReadOnlyDictionary<string, string> attributes)

Parameters

id string

The raw principal id (e.g., a JWT sub claim value).

permissions IReadOnlySet<string>

The set of permissions granted to the actor.

forbiddenPermissions IReadOnlySet<string>

Permissions explicitly denied for this actor.

attributes IReadOnlyDictionary<string, string>

Contextual ABAC attributes.

Exceptions

ArgumentException

Thrown when id is null, empty, or whitespace.

ArgumentNullException

Thrown when permissions, forbiddenPermissions, or attributes is null.

Actor(ActorId, IReadOnlySet<string>, IReadOnlySet<string>, IReadOnlyDictionary<string, string>)

Initializes a new Actor and snapshots the supplied authorization state.

[JsonConstructor]
public Actor(ActorId id, IReadOnlySet<string> permissions, IReadOnlySet<string> forbiddenPermissions, IReadOnlyDictionary<string, string> attributes)

Parameters

id ActorId

The unique identifier of the actor (e.g., user ID from JWT sub claim).

permissions IReadOnlySet<string>

The set of permissions granted to the actor. Implementations such as HashSet<T> and FrozenSet<T> provide O(1) lookups. Scoped permissions must use the PermissionScopeSeparator convention (e.g. "Document.Edit:Tenant_A") so they round-trip correctly through HasPermission(string, string).

forbiddenPermissions IReadOnlySet<string>

Permissions that are explicitly denied for this actor. A permission present in both permissions and forbiddenPermissions is treated as denied (deny always overrides allow).

attributes IReadOnlyDictionary<string, string>

Contextual attributes for attribute-based access control (ABAC). Stores environmental metadata such as IP address, MFA status, risk score, or VPN status. Use ActorAttributes constants for well-known keys.

Exceptions

ArgumentNullException

Thrown when id, permissions, forbiddenPermissions, or attributes is null.

Fields

PermissionScopeSeparator

The separator used between permission name and scope in scoped permission strings.

public const char PermissionScopeSeparator = ':'

Field Value

char

Properties

Attributes

Contextual attributes for attribute-based access control (ABAC).

public IReadOnlyDictionary<string, string> Attributes { get; init; }

Property Value

IReadOnlyDictionary<string, string>

ForbiddenPermissions

Permissions that are explicitly denied for this actor.

public IReadOnlySet<string> ForbiddenPermissions { get; init; }

Property Value

IReadOnlySet<string>

Id

The unique identifier of the actor (e.g., user ID from JWT sub claim). Strongly typed via ActorId so the principal identity flows through authorization-layer APIs and consumer aggregate fields as a domain type rather than an untyped string.

public ActorId Id { get; init; }

Property Value

ActorId

Permissions

The set of permissions granted to the actor. Scoped permissions use the PermissionScopeSeparator convention (e.g. "Document.Edit:Tenant_A") — the format HasPermission(string, string) reconstructs at lookup time.

public IReadOnlySet<string> Permissions { get; init; }

Property Value

IReadOnlySet<string>

Methods

Create(string, IReadOnlySet<string>)

Convenience factory that accepts the actor id as a raw string (typically a claim value at the authentication boundary) and wraps it in ActorId. Authors writing typed application code should prefer the Create(ActorId, IReadOnlySet<string>) overload.

public static Actor Create(string id, IReadOnlySet<string> permissions)

Parameters

id string

The raw principal id (e.g., a JWT sub claim value).

permissions IReadOnlySet<string>

The set of permissions granted to the actor.

Returns

Actor

A new Actor instance.

Exceptions

ArgumentException

Thrown when id is null, empty, or whitespace.

ArgumentNullException

Thrown when permissions is null.

Create(ActorId, IReadOnlySet<string>)

Creates an Actor with no forbidden permissions and no ABAC attributes. Convenience factory for the common case where only identity and permissions are needed.

public static Actor Create(ActorId id, IReadOnlySet<string> permissions)

Parameters

id ActorId

The unique identifier of the actor.

permissions IReadOnlySet<string>

The set of permissions granted to the actor.

Returns

Actor

A new Actor instance.

Exceptions

ArgumentNullException

Thrown when id or permissions is null.

Equals(object?)

Determines whether the specified object is equal to the current object.

public override bool Equals(object? obj)

Parameters

obj object

The object to compare with the current object.

Returns

bool

true if the specified object is equal to the current object; otherwise, false.

Equals(Actor?)

Determines whether the specified Actor represents the same principal.

public bool Equals(Actor? other)

Parameters

other Actor

The actor to compare against.

Returns

bool

true when both actors share the same Id (ordinal comparison); otherwise false. The other properties (Permissions, ForbiddenPermissions, Attributes) are state about the principal, not part of identity, and are intentionally excluded from the equality comparison.

Remarks

Identity-based equality mirrors the domain-layer Trellis.Entity<TId> pattern without inheriting the full IAggregate contract. Two Actors with the same Id represent the same principal even when one carries a freshly-rotated permission set or a different request-bound IP address — both are point-in-time snapshots of the same actor.

GetAttribute(string)

Returns the value of the specified attribute, or null if the attribute does not exist.

public string? GetAttribute(string key)

Parameters

key string

The attribute key. Use ActorAttributes constants for well-known keys.

Returns

string

The attribute value if found; otherwise null.

Exceptions

ArgumentNullException

Thrown when key is null.

GetHashCode()

Serves as the default hash function.

public override int GetHashCode()

Returns

int

A hash code for the current object.

Remarks

The hash is derived from Id only, matching the identity-based equality contract on Equals(Actor?).

GetRequiredAttribute<TVo>(string)

Returns the attribute identified by key parsed into the value object TVo through its IParsable<TSelf> implementation, so a claim-sourced value is validated by the same domain rule that guards request input. Works for any backing primitive — string-, Guid-, int-, or decimal-backed value objects alike.

public Result<TVo> GetRequiredAttribute<TVo>(string key) where TVo : class, IParsable<TVo>

Parameters

key string

The attribute key. Use ActorAttributes constants for well-known keys.

Returns

Result<TVo>

A success Result<TValue> with the typed value when the attribute is present and valid; otherwise a failed Result<TValue> with an Error.InvalidInput whose field is the attribute key. A missing attribute is treated as a missing value and fails the same way.

Type Parameters

TVo

A Trellis value object — any source-generated Required*<T> subclass (for example RequiredString, RequiredGuid, RequiredInt), which the generator makes IParsable<TSelf>. The attribute string is parsed and validated through the type's own TryParse, which routes through its TryCreate validation.

Exceptions

ArgumentNullException

Thrown when key is null.

HasAllPermissions(IEnumerable<string>)

Returns true if this actor has ALL of the specified permissions. Each permission is checked against ForbiddenPermissions (deny-aware).

public bool HasAllPermissions(IEnumerable<string> permissions)

Parameters

permissions IEnumerable<string>

The permissions to check.

Returns

bool

True if the actor has every specified permission and none are forbidden; otherwise false.

Exceptions

ArgumentNullException

Thrown when permissions is null.

HasAnyPermission(IEnumerable<string>)

Returns true if this actor has ANY of the specified permissions. Each permission is checked against ForbiddenPermissions (deny-aware).

public bool HasAnyPermission(IEnumerable<string> permissions)

Parameters

permissions IEnumerable<string>

The permissions to check.

Returns

bool

True if the actor has at least one non-forbidden specified permission; otherwise false.

Exceptions

ArgumentNullException

Thrown when permissions is null.

HasAttribute(string)

Returns true if this actor has the specified attribute.

public bool HasAttribute(string key)

Parameters

key string

The attribute key. Use ActorAttributes constants for well-known keys.

Returns

bool

True if the attribute exists; otherwise false.

Exceptions

ArgumentNullException

Thrown when key is null.

HasPermission(string)

Returns true if this actor has the specified permission and it is not forbidden. If the permission exists in both Permissions and ForbiddenPermissions, deny wins and this returns false.

public bool HasPermission(string permission)

Parameters

permission string

The permission to check (case-sensitive, ordinal comparison).

Returns

bool

True if the permission is granted and not explicitly denied; otherwise false.

Exceptions

ArgumentNullException

Thrown when permission is null.

HasPermission(string, string)

Returns true if this actor has the specified permission within the given scope and it is not forbidden. Uses the "Permission:Scope" convention with PermissionScopeSeparator.

public bool HasPermission(string permission, string scope)

Parameters

permission string

The base permission (e.g., "Document.Edit").

scope string

The scope qualifier (e.g., "Tenant_A" or a resource ID). Case-sensitive.

Returns

bool

True if the scoped permission is granted and not explicitly denied; otherwise false.

Exceptions

ArgumentNullException

Thrown when permission or scope is null.

IsOwner(string)

Convenience overload that accepts the resource owner id as a raw string. Authors writing typed application code should prefer IsOwner(ActorId) so the comparison is type-checked at the call site.

public bool IsOwner(string resourceOwnerId)

Parameters

resourceOwnerId string

The identifier of the resource owner.

Returns

bool

True if the actor's ID matches the resource owner ID; otherwise false.

Exceptions

ArgumentNullException

Thrown when resourceOwnerId is null.

IsOwner(ActorId)

Returns true if this actor is the owner of the specified resource. Compares the actor's Id against the resource owner id using ActorId's value-equality semantics (ordinal string comparison).

public bool IsOwner(ActorId resourceOwnerId)

Parameters

resourceOwnerId ActorId

The identifier of the resource owner (e.g., creator's actor id).

Returns

bool

True if the actor's ID matches the resource owner ID; otherwise false.

Exceptions

ArgumentNullException

Thrown when resourceOwnerId is null.

TryGetAttribute<TVo>(string, out TVo?)

Attempts to parse the attribute identified by key into the value object TVo through its IParsable<TSelf> implementation.

public bool TryGetAttribute<TVo>(string key, out TVo? value) where TVo : class, IParsable<TVo>

Parameters

key string

The attribute key. Use ActorAttributes constants for well-known keys.

value TVo

When this method returns true, the parsed value; otherwise null.

Returns

bool

true when the attribute is present and valid; false when it is absent or fails the value object's validation.

Type Parameters

TVo

A Trellis value object — any source-generated Required*<T> subclass (string-, Guid-, int-backed, and so on), which the generator makes IParsable<TSelf>.

Exceptions

ArgumentNullException

Thrown when key is null.

Operators

operator ==(Actor?, Actor?)

Determines whether two actors represent the same principal (identity-based comparison).

public static bool operator ==(Actor? left, Actor? right)

Parameters

left Actor

The first actor to compare.

right Actor

The second actor to compare.

Returns

bool

true when both operands are null, or when both share the same Id; otherwise false.

operator !=(Actor?, Actor?)

Determines whether two actors represent different principals.

public static bool operator !=(Actor? left, Actor? right)

Parameters

left Actor

The first actor to compare.

right Actor

The second actor to compare.

Returns

bool

true when the actors have different Ids or exactly one is null; otherwise false.