#### [Abblix\.Jwt](https://www.abblix.com/en/docs/api/abblix-jwt 'index')
### [Abblix\.Jwt\.ReplayPrevention](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ReplayPrevention 'Abblix\.Jwt\.ReplayPrevention')

## IReplayCache Interface

Remembers the identifiers of single\-use tokens so a second presentation of the same one can
be told from the first\. Every JWT profile that forbids replay needs this and needs it in the
same shape \- a DPoP proof \(RFC 9449 Section 11\.1\), a client assertion \(RFC 7523 Section 3\)
and a Security Event Token \(RFC 8417 Section 2\.2\) differ in what they call the identifier and
how long it stays interesting, never in the question they ask of the cache\.

```csharp
public interface IReplayCache
```

Derived  
↳ [ReplayCacheBase](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ReplayPrevention.ReplayCacheBase 'Abblix\.Jwt\.ReplayPrevention\.ReplayCacheBase')

### Remarks
The contract is reserve\-and\-check in one call, so a caller cannot read, decide and write in
three steps that another caller slips between\. Whether the reservation is strictly atomic is
the implementation's promise, not this interface's: the shipped
[DistributedReplayCache](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ReplayPrevention.DistributedReplayCache 'Abblix\.Jwt\.ReplayPrevention\.DistributedReplayCache') rides `IDistributedCache`, which exposes only Get
and Set, so its answer is probabilistic within one cache round trip\. A deployment that needs
strict single\-use takes a backend\-native primitive behind this same interface, which is what
[ReplayCacheBase](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ReplayPrevention.ReplayCacheBase 'Abblix\.Jwt\.ReplayPrevention\.ReplayCacheBase') is for: it holds everything around the primitive and leaves the
primitive itself to a subclass \- Redis `SET NX PX`, SQL
`INSERT ... ON CONFLICT DO NOTHING`, and their equivalents\.
### Methods

## IReplayCache\.TryReserveAsync\(string, DateTimeOffset, CancellationToken\) Method {#Abblix.Jwt.ReplayPrevention.IReplayCache.TryReserveAsync(string,System.DateTimeOffset,System.Threading.CancellationToken)}

Reserves an identifier, answering whether this is its first sighting\.

```csharp
System.Threading.Tasks.Task<bool> TryReserveAsync(string identifier, System.DateTimeOffset expiresAt, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
```
#### Parameters

###### `identifier` [System\.String](https://learn.microsoft.com/en-us/dotnet/api/system.string 'System\.String') {#Abblix.Jwt.ReplayPrevention.IReplayCache.TryReserveAsync(string,System.DateTimeOffset,System.Threading.CancellationToken).identifier}

What identifies the token\. A profile whose identifier is unique only within a scope
composes that scope into the value it passes \- a SET's "jti" is unique per event feed
\(RFC 8417 Section 2\.2\), so its receiver reserves the issuer and the identifier together\.

###### `expiresAt` [System\.DateTimeOffset](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset 'System\.DateTimeOffset') {#Abblix.Jwt.ReplayPrevention.IReplayCache.TryReserveAsync(string,System.DateTimeOffset,System.Threading.CancellationToken).expiresAt}

When the identifier stops being worth remembering, which is the last moment a replay of
this token could still pass the caller's own freshness checks\. Forgetting earlier would
let that token replay; the implementation is free to remember longer\.

###### `cancellationToken` [System\.Threading\.CancellationToken](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken 'System\.Threading\.CancellationToken') {#Abblix.Jwt.ReplayPrevention.IReplayCache.TryReserveAsync(string,System.DateTimeOffset,System.Threading.CancellationToken).cancellationToken}

Cancels the cache round trip\.

#### Returns
[System\.Threading\.Tasks\.Task&lt;](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1 'System\.Threading\.Tasks\.Task\`1')[System\.Boolean](https://learn.microsoft.com/en-us/dotnet/api/system.boolean 'System\.Boolean')[&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1 'System\.Threading\.Tasks\.Task\`1')  
True when the identifier was newly reserved and the token is therefore fresh; false when
it was already there, which is a replay\.
