.NET API
IRunAuthorizationHandler
Tracon.Abstractions.dllDecides whether a caller may start a run or read/write a session.
public interface IRunAuthorizationHandlerRemarks
Section titled “Remarks”Tracon draws ownership at the TENANT level. Without this handler, every
Operator in a tenant can start a run as, read, and delete every
other user’s runs and sessions in the same tenant. This interface does not
teach Tracon that boundary — it asks the consumer to enforce their own.
One narrower boundary IS built in, for sessions only: TraconSessionOwnershipOptions records which user opened a session and narrows the session listing to that user. It is off by default, and it does not replace this handler — it answers “which user owns this session” so that a handler no longer has to reject a whole listing just to keep users apart, and leaves every other question (runs, attachments, approvals, scores, per-project rules) to the consumer’s own policy. The two compose: both are consulted, and either can refuse.
The default implementation (AllowAllRunAuthorizationHandler,
registered with TryAdd) allows every call, so an installation that
registers nothing keeps today’s behavior exactly. A consumer replaces the
registration to enforce their own rule.
If this handler throws, the call is denied (fail-closed). A gate that fails open on an exception is not a gate. The same rule IToolAuthorizationHandler follows.
A throw is reported as a failed check, not as a decision. Tracon writes
one error log line in the Tracon.RunAuthorization category with
the handler type, the access kind and the tenant, agent, run and session
identifiers, and the exception. The exception text never reaches the HTTP
response. A 403 then says that the check failed and can be retried;
a 404 stays identical to the answer for a resource that does not
exist. An OperationCanceledException that the request’s own
cancellation did not cause (for example, an HttpClient timeout inside
the handler) counts as a failure too.
The implementation must be a singleton, for the same
reason as IRunAttributionContext: singleton services take a
dependency on it, and a scoped registration would be a captive dependency.
Resolve per-request state through IHttpContextAccessor.
Tenant mode: expected tenant. Every request carries its own
TenantId, resolved by the caller before the handler is invoked; the
handler never reads ITenantContext itself. This is deliberate:
a queued run’s authorization is checked before the tenant’s ambient scope
(AmbientTenantScope) is necessarily active.
Delivery guarantee: no delivery guarantee applies. This is a synchronous decision, not a retried or queued operation — each call is made once, on the request thread, and its result is not persisted or replayed.
Methods
Section titled “Methods”AuthorizeRunAsync(RunAuthorizationRequest, CancellationToken)
Section titled “ AuthorizeRunAsync(RunAuthorizationRequest, CancellationToken)”Decides whether the run described by request may start.
ValueTask<RunAuthorizationResult> AuthorizeRunAsync(RunAuthorizationRequest request, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”request RunAuthorizationRequest
The run being authorized.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<RunAuthorizationResult>
The decision.
AuthorizeSessionAsync(SessionAuthorizationRequest, CancellationToken)
Section titled “ AuthorizeSessionAsync(SessionAuthorizationRequest, CancellationToken)”Decides whether the session access described by request may proceed.
ValueTask<RunAuthorizationResult> AuthorizeSessionAsync(SessionAuthorizationRequest request, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”request SessionAuthorizationRequest
The session access being authorized.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<RunAuthorizationResult>
The decision.