Class DataProtectingPersistedGrantStore
- Namespace
- Fdyay.IdentityServer.Stores
- Assembly
- Fdyay.IdentityServer.Core.dll
Protects a persisted grant's Data on the way into the store and back out of it.
public sealed class DataProtectingPersistedGrantStore : IPersistedGrantStore
- Inheritance
-
DataProtectingPersistedGrantStore
- Implements
- Inherited Members
Remarks
A decorator over the grant store rather than a change to the four stores that write grants,
and the reason is the one this tree keeps paying for. Consent, authorization codes, reference tokens and
refresh tokens each serialize into Data; the device-flow store writes grants too. Protecting at each
of them is five edits and a sixth store away from being wrong again — note 11 with five halves. Here there
is one place, it sits exactly where the value crosses into storage, and a store added later inherits it by
existing.
Only Data is touched. Key is what a lookup is by, and SubjectId,
ClientId, SessionId, Type and the timestamps are what
PersistedGrantFilter queries on — protecting any of them would make the store unable to find
its own rows. That is a real limit and worth stating rather than implying: this protects the contents
of a grant, not the fact that a subject has one.
Reading never consults the option that governs writing, which is what makes an upgrade safe in both directions; see IGrantDataProtector.
Constructors
DataProtectingPersistedGrantStore(IPersistedGrantStore, IGrantDataProtector)
Protection in front of inner.
public DataProtectingPersistedGrantStore(IPersistedGrantStore inner, IGrantDataProtector protector)
Parameters
innerIPersistedGrantStoreThe store that holds the grants, resolved by InnerStoreKey.
protectorIGrantDataProtectorWhat protects
Dataon write and unprotects it on read.
Fields
InnerStoreKey
The key the store being wrapped is registered under.
public const string InnerStoreKey = "Fdyay.IdentityServer.PersistedGrantStore.Unprotected"
Field Value
Remarks
A key rather than the plain service type, because the wrapper is registered as that service type itself.
ProtectPersistedGrantData() moves whatever was registered here, so the container still owns the
inner store's lifetime and its disposal.
Methods
GetAllAsync(PersistedGrantFilter, CancellationToken)
Gets all grants matching the filter.
public Task<IEnumerable<PersistedGrant>> GetAllAsync(PersistedGrantFilter filter, CancellationToken cancellationToken = default)
Parameters
filterPersistedGrantFiltercancellationTokenCancellationToken
Returns
GetAsync(string, CancellationToken)
Gets a grant by key, or null if not found.
public Task<PersistedGrant?> GetAsync(string key, CancellationToken cancellationToken = default)
Parameters
keystringcancellationTokenCancellationToken
Returns
RemoveAllAsync(PersistedGrantFilter, CancellationToken)
Removes all grants matching the filter.
public Task RemoveAllAsync(PersistedGrantFilter filter, CancellationToken cancellationToken = default)
Parameters
filterPersistedGrantFiltercancellationTokenCancellationToken
Returns
RemoveAsync(string, CancellationToken)
Removes a grant by key.
public Task RemoveAsync(string key, CancellationToken cancellationToken = default)
Parameters
keystringcancellationTokenCancellationToken
Returns
StoreAsync(PersistedGrant, CancellationToken)
Stores a grant.
public Task StoreAsync(PersistedGrant grant, CancellationToken cancellationToken = default)
Parameters
grantPersistedGrantcancellationTokenCancellationToken
Returns
TryConsumeAsync(string, DateTime, CancellationToken)
Marks a grant consumed at consumedTime, unless it is gone or consumed already.
public Task<bool> TryConsumeAsync(string key, DateTime consumedTime, CancellationToken cancellationToken = default)
Parameters
keystringThe grant's key.
consumedTimeDateTimeWhen it was consumed, written to ConsumedTime.
cancellationTokenCancellationTokenCancels the write.
Returns
- Task<bool>
True when this call consumed the grant; false when it was gone or another call had consumed it.
Remarks
The same guarantee as TryRemoveAsync(string, CancellationToken) for a one-time refresh token, which is consumed rather than removed so that a later presentation is recognised as a replay. The in-memory, Dapper and data-protecting stores consume in one step; this default reads, checks and writes back, as consuming did before 0.176.0.
TryRemoveAsync(string, CancellationToken)
Removes a grant by key, saying whether this call is the one that removed it.
public Task<bool> TryRemoveAsync(string key, CancellationToken cancellationToken = default)
Parameters
keystringThe grant's key.
cancellationTokenCancellationTokenCancels the removal.
Returns
Remarks
What makes a one-time grant — an authorization code, a refresh token deleted on use — redeemable once when two requests present it at the same moment: both may read it, and only the one whose removal took it goes on. Ours (security), 0.176.0; Duende's store has no such member and its callers read, then remove.
The in-memory, Dapper and data-protecting stores take the grant in one step. This default, for a store of a host's own written before 0.176.0, reads and then removes — correct, and as open to the race as every store was before; a store that can delete and count the rows deleted in one statement should implement it.