Skip to content

Commit 488d0bc

Browse files
authored
Merge pull request #233 from petrsnd/bugfix/petrsnd/device-code-empty-client-id
Fix device code login: default to empty client_id so token redemption succeeds
2 parents 2017eda + b7c95b0 commit 488d0bc

2 files changed

Lines changed: 17 additions & 4 deletions

File tree

SafeguardDotNet.DeviceCodeLogin/DeviceCodeLogin.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,17 @@ public static async Task<ISafeguardConnection> ConnectAsync(
7070
throw new ArgumentException("DisplayCallback is required.", nameof(parameters));
7171
}
7272

73-
var clientId = parameters.ClientId ?? "SafeguardDotNet";
73+
var clientId = parameters.ClientId ?? string.Empty;
7474
var scope = parameters.Scope ?? "rsts:sts:primaryproviderid:local";
7575

76+
// RSTS normalizes empty client_id to its built-in ApplicationClientId in
77+
// both the device-code cache (OAuthTokenManager.GetDeviceCode) and the
78+
// browser-completion path (LoginController.ProcessDeviceLogin). When the
79+
// user finishes via verification_uri_complete, RSTS never propagates a
80+
// non-empty cached client_id to the auth code; the JWT clientIdClaim is
81+
// baked as ApplicationClientId. Sending an empty client_id here makes
82+
// the polling-side comparison value also normalize to ApplicationClientId,
83+
// so both browser flows succeed end-to-end.
7684
using var http = Safeguard.AgentBasedLoginUtils.CreateStatelessHttpClient(ignoreSsl);
7785

7886
// Step 1: Request device code (CRITICAL: no trailing slash on URL)

SafeguardDotNet.DeviceCodeLogin/DeviceCodeLoginParameters.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ public class DeviceCodeLoginParameters
2626

2727
/// <summary>
2828
/// OAuth2 client identifier for the device authorization request.
29-
/// Default: "SafeguardDotNet". Only change if the appliance has
30-
/// RelyingPartyApplications configured with a specific client_id.
29+
/// Defaults to empty, which RSTS normalizes to its built-in
30+
/// ApplicationClientId. Only set this when the appliance has a
31+
/// RelyingPartyApplication registered with a matching client_id; any
32+
/// other non-empty value will fail token redemption when the user
33+
/// completes the flow via the verification_uri_complete URL because
34+
/// RSTS bakes ApplicationClientId into the auth code in that path
35+
/// while comparing it to the cached client_id during polling.
3136
/// </summary>
32-
public string ClientId { get; set; } = "SafeguardDotNet";
37+
public string ClientId { get; set; } = string.Empty;
3338

3439
/// <summary>
3540
/// Polling interval in seconds between token requests. Default: 5 (RFC 8628 default).

0 commit comments

Comments
 (0)