#### [Abblix\.SecurityEvents](https://www.abblix.com/en/docs/api/abblix-securityevents 'index')
### [Abblix\.SecurityEvents\.Delivery](https://www.abblix.com/en/docs/api/abblix-securityevents/Abblix.SecurityEvents.Delivery 'Abblix\.SecurityEvents\.Delivery')

## PushDeliveryHandler Class

The host\-agnostic core of a push delivery endpoint \(RFC 8935\): one method from the raw
transmission \- content type and body \- to the [PushDeliveryResult](https://www.abblix.com/en/docs/api/abblix-securityevents/Abblix.SecurityEvents.Delivery.PushDeliveryResult 'Abblix\.SecurityEvents\.Delivery\.PushDeliveryResult') the transport
renders\. A host adapter owns routing and transmitter authentication; this type owns everything
the specifications say about the SET itself\.

```csharp
public sealed class PushDeliveryHandler
```

Inheritance [System\.Object](https://learn.microsoft.com/en-us/dotnet/api/system.object 'System\.Object') → PushDeliveryHandler

### Remarks

The order inside is the security order. Validation decides first, so an attacker cannot burn
replay identifiers with forgeries; the sink then consumes what validation let through; and only
a token the sink accepted is written to the replay cache. Nothing on this path READS that cache,
so a redelivery reaches the sink again - RFC 8935 Section 2 lets a transmitter redeliver
regardless of earlier responses, and [ISecurityEventSink](https://www.abblix.com/en/docs/api/abblix-securityevents/Abblix.SecurityEvents.Delivery.ISecurityEventSink 'Abblix\.SecurityEvents\.Delivery\.ISecurityEventSink') answers for it by
requiring idempotent processing. Why the write cannot come earlier, and why that is the only
correct order available here, is on `RecordAsync`.

Nothing here knows which profile of SET it carries. RFC 8935 is a delivery specification and
the kinds it delivers are somebody else's business, so the three things that differ between
consumers - the validation profile, what that profile expects, and where events land - arrive
as parameters. The consumer's own registration binds them, which is also why the profile
cannot be named by a keyed-service attribute here: an attribute takes a compile-time constant,
and the key belongs to whoever registers this.
### Constructors

## PushDeliveryHandler\(ISecurityEventTokenValidator, SecurityEventTokenValidationOptions, ISecurityEventSink, IReplayCache\) Constructor {#Abblix.SecurityEvents.Delivery.PushDeliveryHandler.PushDeliveryHandler(Abblix.SecurityEvents.Validation.ISecurityEventTokenValidator,Abblix.SecurityEvents.Validation.SecurityEventTokenValidationOptions,Abblix.SecurityEvents.Delivery.ISecurityEventSink,Abblix.Jwt.ReplayPrevention.IReplayCache)}

The host\-agnostic core of a push delivery endpoint \(RFC 8935\): one method from the raw
transmission \- content type and body \- to the [PushDeliveryResult](https://www.abblix.com/en/docs/api/abblix-securityevents/Abblix.SecurityEvents.Delivery.PushDeliveryResult 'Abblix\.SecurityEvents\.Delivery\.PushDeliveryResult') the transport
renders\. A host adapter owns routing and transmitter authentication; this type owns everything
the specifications say about the SET itself\.

```csharp
public PushDeliveryHandler(Abblix.SecurityEvents.Validation.ISecurityEventTokenValidator validator, Abblix.SecurityEvents.Validation.SecurityEventTokenValidationOptions options, Abblix.SecurityEvents.Delivery.ISecurityEventSink sink, Abblix.Jwt.ReplayPrevention.IReplayCache? replayCache=null);
```
#### Parameters

###### `validator` [ISecurityEventTokenValidator](https://www.abblix.com/en/docs/api/abblix-securityevents/Abblix.SecurityEvents.Validation.ISecurityEventTokenValidator 'Abblix\.SecurityEvents\.Validation\.ISecurityEventTokenValidator') {#Abblix.SecurityEvents.Delivery.PushDeliveryHandler.PushDeliveryHandler(Abblix.SecurityEvents.Validation.ISecurityEventTokenValidator,Abblix.SecurityEvents.Validation.SecurityEventTokenValidationOptions,Abblix.SecurityEvents.Delivery.ISecurityEventSink,Abblix.Jwt.ReplayPrevention.IReplayCache).validator}

The validation pipeline, which the registering consumer resolves from its OWN named profile \-
never the host's plain family, which another consumer of security event tokens may have shaped
to refuse every SET of this kind\.

###### `options` [SecurityEventTokenValidationOptions](https://www.abblix.com/en/docs/api/abblix-securityevents/Abblix.SecurityEvents.Validation.SecurityEventTokenValidationOptions 'Abblix\.SecurityEvents\.Validation\.SecurityEventTokenValidationOptions') {#Abblix.SecurityEvents.Delivery.PushDeliveryHandler.PushDeliveryHandler(Abblix.SecurityEvents.Validation.ISecurityEventTokenValidator,Abblix.SecurityEvents.Validation.SecurityEventTokenValidationOptions,Abblix.SecurityEvents.Delivery.ISecurityEventSink,Abblix.Jwt.ReplayPrevention.IReplayCache).options}

What that consumer expects of every token it accepts\.

###### `sink` [ISecurityEventSink](https://www.abblix.com/en/docs/api/abblix-securityevents/Abblix.SecurityEvents.Delivery.ISecurityEventSink 'Abblix\.SecurityEvents\.Delivery\.ISecurityEventSink') {#Abblix.SecurityEvents.Delivery.PushDeliveryHandler.PushDeliveryHandler(Abblix.SecurityEvents.Validation.ISecurityEventTokenValidator,Abblix.SecurityEvents.Validation.SecurityEventTokenValidationOptions,Abblix.SecurityEvents.Delivery.ISecurityEventSink,Abblix.Jwt.ReplayPrevention.IReplayCache).sink}

Where validated events land\.

###### `replayCache` [IReplayCache](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ReplayPrevention.IReplayCache 'Abblix\.Jwt\.ReplayPrevention\.IReplayCache') {#Abblix.SecurityEvents.Delivery.PushDeliveryHandler.PushDeliveryHandler(Abblix.SecurityEvents.Validation.ISecurityEventTokenValidator,Abblix.SecurityEvents.Validation.SecurityEventTokenValidationOptions,Abblix.SecurityEvents.Delivery.ISecurityEventSink,Abblix.Jwt.ReplayPrevention.IReplayCache).replayCache}

Tells first deliveries from repeats; null runs without replay tracking, leaving idempotency
entirely to the sink's contract\.

### Remarks

The order inside is the security order. Validation decides first, so an attacker cannot burn
replay identifiers with forgeries; the sink then consumes what validation let through; and only
a token the sink accepted is written to the replay cache. Nothing on this path READS that cache,
so a redelivery reaches the sink again - RFC 8935 Section 2 lets a transmitter redeliver
regardless of earlier responses, and [ISecurityEventSink](https://www.abblix.com/en/docs/api/abblix-securityevents/Abblix.SecurityEvents.Delivery.ISecurityEventSink 'Abblix\.SecurityEvents\.Delivery\.ISecurityEventSink') answers for it by
requiring idempotent processing. Why the write cannot come earlier, and why that is the only
correct order available here, is on `RecordAsync`.

Nothing here knows which profile of SET it carries. RFC 8935 is a delivery specification and
the kinds it delivers are somebody else's business, so the three things that differ between
consumers - the validation profile, what that profile expects, and where events land - arrive
as parameters. The consumer's own registration binds them, which is also why the profile
cannot be named by a keyed-service attribute here: an attribute takes a compile-time constant,
and the key belongs to whoever registers this.
### Methods

## PushDeliveryHandler\.HandleAsync\(string, string, CancellationToken\) Method {#Abblix.SecurityEvents.Delivery.PushDeliveryHandler.HandleAsync(string,string,System.Threading.CancellationToken)}

Handles one push transmission\.

```csharp
public System.Threading.Tasks.Task<Abblix.SecurityEvents.Delivery.PushDeliveryResult> HandleAsync(string? contentType, string? body, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
```
#### Parameters

###### `contentType` [System\.String](https://learn.microsoft.com/en-us/dotnet/api/system.string 'System\.String') {#Abblix.SecurityEvents.Delivery.PushDeliveryHandler.HandleAsync(string,string,System.Threading.CancellationToken).contentType}

The request's Content\-Type header, as received\.

###### `body` [System\.String](https://learn.microsoft.com/en-us/dotnet/api/system.string 'System\.String') {#Abblix.SecurityEvents.Delivery.PushDeliveryHandler.HandleAsync(string,string,System.Threading.CancellationToken).body}

The request body: one SET in compact serialization\.

###### `cancellationToken` [System\.Threading\.CancellationToken](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken 'System\.Threading\.CancellationToken') {#Abblix.SecurityEvents.Delivery.PushDeliveryHandler.HandleAsync(string,string,System.Threading.CancellationToken).cancellationToken}

Cancels validation I/O and processing\.

#### Returns
[System\.Threading\.Tasks\.Task&lt;](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1 'System\.Threading\.Tasks\.Task\`1')[PushDeliveryResult](https://www.abblix.com/en/docs/api/abblix-securityevents/Abblix.SecurityEvents.Delivery.PushDeliveryResult 'Abblix\.SecurityEvents\.Delivery\.PushDeliveryResult')[&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1 'System\.Threading\.Tasks\.Task\`1')
