Skip to content

Commit 94459a8

Browse files
committed
Fix device code login to send empty client_id
Sending a non-empty client_id caused token redemption to fail with "invalid_request" when the user completed authentication via the verification_uri_complete URL (the URL with the code already embedded). The manual code-entry path was unaffected. Defaulting DeviceCodeLoginParameters.ClientId to empty string makes both completion paths succeed against rSTS. Non-empty values still work, but only when the appliance has a matching RelyingPartyApplication registered; this caveat is now documented on the property.
1 parent f029d74 commit 94459a8

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
@@ -72,9 +72,17 @@ public static async Task<ISafeguardConnection> ConnectAsync(
7272
throw new ArgumentException("DisplayCallback is required.", nameof(parameters));
7373
}
7474

75-
var clientId = parameters.ClientId ?? "SafeguardDotNet";
75+
var clientId = parameters.ClientId ?? string.Empty;
7676
var scope = parameters.Scope ?? "rsts:sts:primaryproviderid:local";
7777

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

8088
// 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)