# IRunAuthorizationHandler

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.irunauthorizationhandler/
> Summary: IRunAuthorizationHandler: Decides whether a caller may start a run or read/write a session.

<div class="api-provenance">Namespace Tracon · Assembly <code>Tracon.Abstractions.dll</code></div>

Decides whether a caller may start a run or read/write a session.

```csharp
public interface IRunAuthorizationHandler
```

## 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](/api/tracon.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](/api/tracon.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](https://learn.microsoft.com/dotnet/api/system.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](/api/tracon.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](/api/tracon.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

### <a id="Tracon_IRunAuthorizationHandler_AuthorizeRunAsync_Tracon_RunAuthorizationRequest_System_Threading_CancellationToken_"></a> AuthorizeRunAsync\(RunAuthorizationRequest, CancellationToken\)

Decides whether the run described by `request` may start.

```csharp
ValueTask<RunAuthorizationResult> AuthorizeRunAsync(RunAuthorizationRequest request, CancellationToken cancellationToken = default)
```

#### Parameters

`request` [RunAuthorizationRequest](/api/tracon.runauthorizationrequest/)

The run being authorized.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[RunAuthorizationResult](/api/tracon.runauthorizationresult/)\>

The decision.

### <a id="Tracon_IRunAuthorizationHandler_AuthorizeSessionAsync_Tracon_SessionAuthorizationRequest_System_Threading_CancellationToken_"></a> AuthorizeSessionAsync\(SessionAuthorizationRequest, CancellationToken\)

Decides whether the session access described by `request` may proceed.

```csharp
ValueTask<RunAuthorizationResult> AuthorizeSessionAsync(SessionAuthorizationRequest request, CancellationToken cancellationToken = default)
```

#### Parameters

`request` [SessionAuthorizationRequest](/api/tracon.sessionauthorizationrequest/)

The session access being authorized.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[RunAuthorizationResult](/api/tracon.runauthorizationresult/)\>

The decision.
