Skip to content

Conversation

@jon4hz
Copy link

@jon4hz jon4hz commented Jan 2, 2026

What issue does this PR address?

Hi,

This PR fixes a bug in the device authentication. According to rfc 8628, the device authorization request must contain a client_id and optionally a scope.
However, the http client extension you are providing, omits the client id from the request. This causes all device auth requests to fail with:

Device authorization failed: invalid_client - Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)

Copilot AI review requested due to automatic review settings January 2, 2026 20:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a bug where device authorization requests were missing the required client_id parameter per RFC 8628. The fix adds the client_id to the request parameters, however the implementation has a critical issue that needs to be corrected.

Key changes:

  • Adds client_id parameter to device authorization requests using AddRequired

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

var clone = request.Clone();

clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.Scope, request.Scope);
clone.Parameters.AddRequired(OidcConstants.AuthorizeRequest.ClientId, request.ClientId);
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client_id should only be added to parameters when ClientCredentialStyle is AuthorizationHeader. When ClientCredentialStyle is PostBody, the Prepare() method (called on line 27) already adds the client_id to the request body. Adding it unconditionally will cause the client_id to be duplicated in the request body when using PostBody authentication style.

The correct pattern (as seen in HttpClientPushedAuthorizationExtensions.cs lines 29-34) is:

// client id is always required, and will be added by the call to
// Prepare() for other client credential styles.
if (request.ClientCredentialStyle == ClientCredentialStyle.AuthorizationHeader)
{
    clone.Parameters.AddRequired(OidcConstants.AuthorizeRequest.ClientId, request.ClientId);
}

This ensures that:

  • When using AuthorizationHeader style: credentials go in the Authorization header, but client_id is still sent in the body (per RFC 8628)
  • When using PostBody style: Prepare() handles adding both client_id and client_secret to the body
Suggested change
clone.Parameters.AddRequired(OidcConstants.AuthorizeRequest.ClientId, request.ClientId);
// client id is always required, and will be added by the call to
// Prepare() for other client credential styles.
if (request.ClientCredentialStyle == ClientCredentialStyle.AuthorizationHeader)
{
clone.Parameters.AddRequired(OidcConstants.AuthorizeRequest.ClientId, request.ClientId);
}

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like copilot is right and the client_id is set if I explicitly set the ClientCredentialStyle to PostBody.

In my opinion, setting the credential style shouldn't be necessary, though, since the device code authentication doesn't require any credentials.

How should I proceed here? I could see a:

if (request.ClientCredentialStyle != ClientCredentialStyle.PostBody) {
    clone.Parameters.AddRequired(OidcConstants.AuthorizeRequest.ClientId, request.ClientId);
}

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant