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

## IKeyRingStore Interface

The shared place the server's minted keys live, so every pod serves one key set rather than its own\. Entries
are encrypted to the custodian's key\-encryption key before they get here, so this store holds ciphertext and
never a secret\.

```csharp
public interface IKeyRingStore
```

### Remarks
The port is three methods because the design needs no more\. Key state is not stored, it is computed: given the
entries and their creation times, every pod derives the same announced / active / retired projection by
arithmetic, so there is nothing to update and no state machine to synchronise\. The single operation that does
need synchronising is creating the next key, since two pods would otherwise generate different material, and
[TryAddAsync\(StoredKey, CancellationToken\)](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ExternalKeys.IKeyRingStore#Abblix.Jwt.ExternalKeys.IKeyRingStore.TryAddAsync(Abblix.Jwt.ExternalKeys.StoredKey,System.Threading.CancellationToken) 'Abblix\.Jwt\.ExternalKeys\.IKeyRingStore\.TryAddAsync\(Abblix\.Jwt\.ExternalKeys\.StoredKey, System\.Threading\.CancellationToken\)') carries that alone\.

Because the entry is ciphertext we produced, the store's own protection is not what keeps the key safe: an
implementation may be a database, a blob, a config map, or the custodian's own key-value engine, and the
threat model does not change with the choice.
### Methods

## IKeyRingStore\.LoadAsync\(CancellationToken\) Method {#Abblix.Jwt.ExternalKeys.IKeyRingStore.LoadAsync(System.Threading.CancellationToken)}

Reads every entry\. The caller projects the key states from their creation times, so the store neither
filters nor orders\.

```csharp
System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Abblix.Jwt.ExternalKeys.StoredKey>> LoadAsync(System.Threading.CancellationToken cancellationToken);
```
#### Parameters

###### `cancellationToken` [System\.Threading\.CancellationToken](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken 'System\.Threading\.CancellationToken') {#Abblix.Jwt.ExternalKeys.IKeyRingStore.LoadAsync(System.Threading.CancellationToken).cancellationToken}

Cancels the read\.

#### 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\.Collections\.Generic\.IReadOnlyList&lt;](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlylist-1 'System\.Collections\.Generic\.IReadOnlyList\`1')[StoredKey](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ExternalKeys.StoredKey 'Abblix\.Jwt\.ExternalKeys\.StoredKey')[&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlylist-1 'System\.Collections\.Generic\.IReadOnlyList\`1')[&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1 'System\.Threading\.Tasks\.Task\`1')  
All entries currently in the ring\.

## IKeyRingStore\.RemoveAsync\(string, CancellationToken\) Method {#Abblix.Jwt.ExternalKeys.IKeyRingStore.RemoveAsync(string,System.Threading.CancellationToken)}

Removes an entry, idempotently: removing an absent id is not an error\.

```csharp
System.Threading.Tasks.Task RemoveAsync(string id, System.Threading.CancellationToken cancellationToken);
```
#### Parameters

###### `id` [System\.String](https://learn.microsoft.com/en-us/dotnet/api/system.string 'System\.String') {#Abblix.Jwt.ExternalKeys.IKeyRingStore.RemoveAsync(string,System.Threading.CancellationToken).id}

The [Id](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ExternalKeys.StoredKey#Abblix.Jwt.ExternalKeys.StoredKey.Id 'Abblix\.Jwt\.ExternalKeys\.StoredKey\.Id') to remove\.

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

Cancels the write\.

#### Returns
[System\.Threading\.Tasks\.Task](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task 'System\.Threading\.Tasks\.Task')

### Remarks
Only ever called for a key already past every token it signed, so removal races are harmless: two pods
removing the same expired entry is the same outcome as one\.

## IKeyRingStore\.TryAddAsync\(StoredKey, CancellationToken\) Method {#Abblix.Jwt.ExternalKeys.IKeyRingStore.TryAddAsync(Abblix.Jwt.ExternalKeys.StoredKey,System.Threading.CancellationToken)}

Inserts an entry if its [Id](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ExternalKeys.StoredKey#Abblix.Jwt.ExternalKeys.StoredKey.Id 'Abblix\.Jwt\.ExternalKeys\.StoredKey\.Id') is not taken, and reports whether this caller was the
one that took it\.

```csharp
System.Threading.Tasks.Task<bool> TryAddAsync(Abblix.Jwt.ExternalKeys.StoredKey key, System.Threading.CancellationToken cancellationToken);
```
#### Parameters

###### `key` [StoredKey](https://www.abblix.com/en/docs/api/abblix-jwt/Abblix.Jwt.ExternalKeys.StoredKey 'Abblix\.Jwt\.ExternalKeys\.StoredKey') {#Abblix.Jwt.ExternalKeys.IKeyRingStore.TryAddAsync(Abblix.Jwt.ExternalKeys.StoredKey,System.Threading.CancellationToken).key}

The entry to insert\.

###### `cancellationToken` [System\.Threading\.CancellationToken](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken 'System\.Threading\.CancellationToken') {#Abblix.Jwt.ExternalKeys.IKeyRingStore.TryAddAsync(Abblix.Jwt.ExternalKeys.StoredKey,System.Threading.CancellationToken).cancellationToken}

Cancels the write\.

#### 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 this caller inserted the entry; false when another pod had already claimed the id, in
            which case the caller re\-reads the ring and uses the winner's key\.

### Remarks
This is the whole of the coordination, and it must be atomic in the backing store: a unique index, a
conditional create, a compare\-and\-set on absence\. Two pods minting the same period both attempt the same
id, exactly one gets true, and the loser discards the key it generated\. An implementation that cannot
insert atomically cannot back this port\.
