Class DapperDeviceFlowStore
- Namespace
- Fdyay.IdentityServer.Dapper.Stores
- Assembly
- Fdyay.IdentityServer.Dapper.dll
Dapper-backed device flow store.
public sealed class DapperDeviceFlowStore : IDeviceFlowStore
- Inheritance
-
DapperDeviceFlowStore
- Implements
- Inherited Members
Remarks
This is the store a multi-instance deployment needs. The device polls whichever instance the load balancer picks while the user approves on whichever instance their browser reached, so with the in-memory default a device can poll forever against an instance that never saw the approval.
The authorization data-protected since 0.177.0, as Duende's operational store serializes it through
IPersistentGrantSerializer (measured): once approved it carries the user's subject, session and grant. A row written
before is still read, through the protector's plaintext fallback. The codes stay columns, as Duende's do: the device and
the user's browser look the row up by them.
Constructors
DapperDeviceFlowStore(IDbConnectionFactory, TimeProvider)
Creates a device flow store over the DeviceFlowCodes table.
public DapperDeviceFlowStore(IDbConnectionFactory connectionFactory, TimeProvider time)
Parameters
connectionFactoryIDbConnectionFactoryOpens a connection for each operation and supplies the dialect's upsert.
timeTimeProviderThe clock reads compare a row's expiry against.
Remarks
Writes each authorization unprotected, as before 0.177.0; the container builds the overload taking a protector.
DapperDeviceFlowStore(IDbConnectionFactory, TimeProvider, IGrantDataProtector)
Creates the store, protecting each authorization with protector.
public DapperDeviceFlowStore(IDbConnectionFactory connectionFactory, TimeProvider time, IGrantDataProtector protector)
Parameters
connectionFactoryIDbConnectionFactoryOpens a connection for each operation and supplies the dialect's upsert.
timeTimeProviderThe clock reads compare a row's expiry against.
protectorIGrantDataProtectorProtects the
Datacolumn as it does a persisted grant's, underPersistentGrants.DataProtectData, and reads a row written unprotected as it was written.
Methods
FindByDeviceCodeAsync(string, CancellationToken)
The authorization stored under a device code, or null.
public Task<DeviceCode?> FindByDeviceCodeAsync(string deviceCode, CancellationToken cancellationToken = default)
Parameters
deviceCodestringThe device code's key.
cancellationTokenCancellationTokenCancels the read.
Returns
- Task<DeviceCode>
The authorization, or null when none is stored under that key.
Remarks
Reads the DeviceFlowCodes row whose DeviceCode matches. A miss returns null, and so does a row whose
ExpiresAtUtc has passed, whether or not the sweep has removed it yet.
Exceptions
- ArgumentException
deviceCodeis null or empty.
FindByUserCodeAsync(string, CancellationToken)
The authorization stored under a user code, or null.
public Task<DeviceCode?> FindByUserCodeAsync(string userCode, CancellationToken cancellationToken = default)
Parameters
userCodestringThe user code's key.
cancellationTokenCancellationTokenCancels the read.
Returns
- Task<DeviceCode>
The authorization, or null when none is stored under that key.
Remarks
Reads the DeviceFlowCodes row whose UserCode matches. A miss returns null, and so does a row whose
ExpiresAtUtc has passed, whether or not the sweep has removed it yet.
Exceptions
- ArgumentException
userCodeis null or empty.
RemoveByDeviceCodeAsync(string, CancellationToken)
Removes the authorization stored under a device code, under both of its keys.
public Task RemoveByDeviceCodeAsync(string deviceCode, CancellationToken cancellationToken = default)
Parameters
deviceCodestringThe device code's key.
cancellationTokenCancellationTokenCancels the removal.
Returns
Remarks
Deletes the DeviceFlowCodes row whose DeviceCode matches. A miss deletes nothing and is not an error.
Exceptions
- ArgumentException
deviceCodeis null or empty.
StoreDeviceAuthorizationAsync(string, string, DeviceCode, CancellationToken)
Stores a new pending authorization under both of its keys.
public Task StoreDeviceAuthorizationAsync(string deviceCode, string userCode, DeviceCode data, CancellationToken cancellationToken = default)
Parameters
deviceCodestringThe device code's key — its hash, as IDeviceFlowCodeService passes it.
userCodestringThe user code's key — its hash, as IDeviceFlowCodeService passes it.
dataDeviceCodeThe authorization.
cancellationTokenCancellationTokenCancels the write.
Returns
Remarks
Upserts the DeviceFlowCodes row keyed by DeviceCode, with the user code, client id and an
ExpiresAtUtc of the authorization's creation time plus its lifetime in seconds as columns and the
authorization itself as JSON. A user code already held by another device code violates the unique index on
UserCode and the provider's exception propagates.
Exceptions
- ArgumentException
deviceCodeoruserCodeis null or empty.- ArgumentNullException
datais null.
UpdateByUserCodeAsync(string, DeviceCode, CancellationToken)
Replaces the authorization stored under a user code, under both of its keys — a user's approval or denial.
public Task UpdateByUserCodeAsync(string userCode, DeviceCode data, CancellationToken cancellationToken = default)
Parameters
userCodestringThe user code's key.
dataDeviceCodeThe authorization as it now stands.
cancellationTokenCancellationTokenCancels the write.
Returns
Remarks
The in-tree stores do nothing when no authorization is stored under userCode.
Exceptions
- ArgumentException
userCodeis null or empty.- ArgumentNullException
datais null.