Class DeviceLinks
Signs in a new device by having the user approve it from a device where they are already signed in. The new device shows a short code, the user types it on the signed-in device, checks the new device's details and approves it, and the new device then receives a one-time sign-in code.
Namespace: Singulink.Net.Http.Api.Service.SignIn
Assembly: Singulink.Net.Http.Api.Service.dll
Syntax
public sealed class DeviceLinks
Remarks
The flow has four steps:
- The new device calls StartAsync(string, string, IPAddress?, string?, CancellationToken) with a PKCE code challenge and shows the returned code.
- On a signed-in device, the user types the code, and FindAsync(string, string, CancellationToken) returns the new device's details to check.
- The user confirms, and ApproveAsync(string, string, string?, CancellationToken) approves the link for them.
- Meanwhile the new device checks the link's status with CheckAsync(string, string, CancellationToken) (or PollAsync(string, string, CancellationToken)). Once the link is approved, the status contains a sign-in code, which the new device redeems with its code verifier (see SignInAsync<TSessionToken>(SessionContext<TSessionToken>, RedeemSignInCodeCommand, Func<RedeemedSignInCode, SignInInfo, Task<TSessionToken>>, CancellationToken)).
Wrong codes count against the user typing them: after 5 wrong codes, FindAsync(string, string, CancellationToken) and ApproveAsync(string, string, string?, CancellationToken) refuse further lookups for that user, so a signed-in account cannot be used to guess codes. The count is forgotten once the link lifetime passes without a lookup by the user (lookups that are refused do not count), so refusals have RetryAfter set to the link lifetime. Input that cannot be a code (see Normalize(string)) is not counted.
Links, wrong code counts and the sign-in codes are kept in the registered IShortLivedStore.
Constructors
| Name | Description |
|---|---|
| DeviceLinks(IShortLivedStore, SignInCodes, IOptions<DeviceLinkOptions>, TimeProvider, ILogger<DeviceLinks>) | Initializes a new instance of the DeviceLinks class. |
Methods
| Name | Description |
|---|---|
| ApproveAsync(string, ISessionToken, string?, CancellationToken) | Approves the device waiting with a code typed by a signed-in user, so that the device is signed in to that user's account, and returns the outcome with the details of the device that was approved. A link can only be approved once. |
| ApproveAsync(string, string, string?, CancellationToken) | Approves the device waiting with a code typed by a signed-in user, so that the device is signed in to that user's account, and returns the outcome with the details of the device that was approved. A link can only be approved once. |
| CheckAsync(string, string, CancellationToken) | Gets the status of a link for the new device, which the app returns to it as-is. Once the link is approved, the status contains a one-time sign-in code bound to the link's code challenge. |
| FindAsync(string, ISessionToken, CancellationToken) | Finds the device waiting with a code typed by a signed-in user and returns its details, or null if no device is waiting with the code or the input cannot be a code. |
| FindAsync(string, string, CancellationToken) | Finds the device waiting with a code typed by a signed-in user and returns its details, or null if no device is waiting with the code or the input cannot be a code. |
| PollAsync(string, string, CancellationToken) | Gets the status of a link for the new device, or returns null if the link is unknown or expired, or the poll secret is wrong. Once the link is approved, the status contains a one-time sign-in code bound to the link's code challenge. |
| StartAsync(string, string, IPAddress?, string?, CancellationToken) | Starts a link for a new device and returns what the new device needs, which the app returns to it as-is: the code to show, the ID and poll secret to check the link's status, and how long the link waits for approval (Lifetime). |