Skip to main content

Attributes

Two attributes ship in the contract. Neither does anything on its own — both are read by hosts at composition time.

[Authorize]

Binds a method or class to a named policy.

[AttributeUsage(
AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple = true,
Inherited = true)]
public sealed class AuthorizeAttribute : Attribute
{
public AuthorizeAttribute(string policyName);
public string PolicyName { get; }
}
PropertyTypeDescription
PolicyNamestringRequired. Non-null, non-empty. Must match an [AuthorizationPolicy("...")] Name registered with the host.

Targets methods or classes. AllowMultiple = true — stacking [Authorize] declarations is supported, and hosts treat the set as a conjunction (every policy must allow). Inherited = true — derived classes inherit class-level placements.

public sealed class UserService
{
[Authorize("AdminOnly")]
public Task DeleteUserAsync(string userId) { /* ... */ return Task.CompletedTask; }

[Authorize("ActiveTenant")]
[Authorize("AdminOnly")]
public Task PurgeTenantAsync(string tenantId) { /* ... */ return Task.CompletedTask; }
}

Behavior is contract-only. The attribute carries no logic — a host reads PolicyName, resolves it to a policy class, and invokes IsAuthorized / IsAuthorizedAsync before dispatch.

[AuthorizationPolicy]

Names a policy class so it can be referenced from [Authorize] and host-specific binding APIs.

[AttributeUsage(
AttributeTargets.Class,
AllowMultiple = false,
Inherited = false)]
public sealed class AuthorizationPolicyAttribute : Attribute
{
public AuthorizationPolicyAttribute(string name);
public string Name { get; }
}
PropertyTypeDescription
NamestringRequired. Non-null, non-empty. The registration name hosts use to map [Authorize("Name")] to this class.

Targets classes only. AllowMultiple = false — one registration name per class. Inherited = false — derived policy classes do not inherit the registration; if a derived class is its own policy it must declare its own [AuthorizationPolicy("...")].

[AuthorizationPolicy("AdminOnly")]
public sealed class AdminOnlyPolicy : IAuthorizationPolicy
{
public bool IsAuthorized(ISecurityContext ctx) => ctx.Roles.Contains("Admin");
}

The class must implement IAuthorizationPolicy. The contract package does not enforce that constraint at compile time — hosts surface registration errors when they build their name→type registry.

Discovery

Hosts scan [AuthorizationPolicy]-attributed types and build a name → Type registry, then resolve [Authorize("Name")].PolicyName against it at dispatch time. The contract package itself performs no scanning, no caching, and no registration — every discovery strategy (assembly walk, source generator, hand-registration) lives in the host.

See Host integration for the registry contract a host is expected to satisfy.