git-ecosystem/git-credential-manager · error · Trace2InvalidOperationException
No device authorization endpoint has been configured for…
Error message
No device authorization endpoint has been configured for this client.
What it means
GetDeviceCodeAsync requires a device authorization endpoint to be configured on the client's endpoint collection (_endpoints.DeviceAuthorizationEndpoint). When the OAuth2 client was created without one, the device code flow cannot even be started, so the library throws Trace2InvalidOperationException before making any network call.
Solutions
- Configure a valid device authorization endpoint on the client's endpoints before calling GetDeviceCodeAsync (typically from the authority's OIDC discovery document).
- Use a modern Azure AD/Entra authority (e.g. https://login.microsoftonline.com/{tenant}) whose discovery document advertises device_authorization_endpoint.
- If endpoints are built manually, add the device authorization endpoint (for Entra: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/devicecode).
- Fall back to a different interaction mode (webview-based) if the authority does not support device code flow.
Example fix
// before
var endpoints = new OAuth2Endpoints(authorizationEndpoint, tokenEndpoint); // no device endpoint
await client.GetDeviceCodeAsync(endpoints, scopes, ct); // throws
// after
var endpoints = new OAuth2Endpoints(authorizationEndpoint, tokenEndpoint,
deviceAuthorizationEndpoint: "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/devicecode");
await client.GetDeviceCodeAsync(endpoints, scopes, ct); Defensive patterns
Strategy: validation
Validate before calling
if (endpoints.DeviceAuthorizationEndpoint is null)
throw new InvalidOperationException("Device authorization endpoint not configured; cannot use device code flow."); Try / catch
try
{
deviceResult = await client.GetDeviceCodeAsync(endpoints, scopes, ct);
}
catch (Trace2InvalidOperationException ex) when (ex.Message.Contains("device authorization endpoint"))
{
// fall back to a webview-based interaction mode or reconfigure endpoints
return AuthFailure.NoDeviceEndpoint;
} Prevention
- Resolve endpoints from the authority's OIDC discovery document rather than building them by hand.
- Verify the discovery metadata contains device_authorization_endpoint before choosing device code flow.
- Use a modern Entra ID authority that supports device code flow.
- Configure a fallback interaction mode when the authority lacks device code support.
When it happens
Trigger: Calling GetDeviceCodeAsync on an OAuth2Client whose endpoints (from the OpenID Connect discovery / authority metadata) lack a device_authorization_endpoint — either the endpoints dictionary was built manually without it or the authority's discovery document does not advertise device code support.
Common situations: Pointing the client at a token endpoint or authority whose metadata does not include device_authorization_endpoint (e.g. some ADFS or on-prem STS configurations); constructing OAuth2Endpoints manually with only token/authorization endpoints; an older authority that predates device code flow support.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- Bitbucket DC OAuth Client ID must be defined
- Bitbucket DC OAuth Client Secret must be defined
- RemoteUri must be defined to generate Bitbucket DC OAuth2…
- RemoteUri must be defined to generate Bitbucket DC OAuth2…
- Cannot prompt because user interactivity has been disabled.
AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11).
Data as JSON: /api/errors/2ac7a013947b0d91.
Report an issue: GitHub.
Appendix: source
Thrown at src/Core/Authentication/OAuth/OAuth2Client.cs:207
// We expect to have the auth code in the response otherwise terminate the flow (we failed authentication for some reason)
if (!responseParams.TryGetValue(OAuth2Constants.AuthorizationGrantResponse.AuthorizationCodeParameter, out string authCode))
{
throw new Trace2OAuth2Exception(_trace2,
$"Missing '{OAuth2Constants.AuthorizationGrantResponse.AuthorizationCodeParameter}' in response.");
}
return new OAuth2AuthorizationCodeResult(authCode, redirectUri, codeVerifier);
}
public async Task<OAuth2DeviceCodeResult> GetDeviceCodeAsync(IEnumerable<string> scopes, CancellationToken ct)
{
var label = "get device code";
using IDisposable region = _trace2.CreateRegion(OAuth2Constants.Trace2Category, label);
if (_endpoints.DeviceAuthorizationEndpoint is null)
{
throw new Trace2InvalidOperationException(_trace2,
"No device authorization endpoint has been configured for this client.");
}
string scopesStr = string.Join(" ", scopes);
var formData = new Dictionary<string, string>
{
[OAuth2Constants.ClientIdParameter] = _clientId
};
if (!string.IsNullOrWhiteSpace(scopesStr))
{
formData[OAuth2Constants.ScopeParameter] = scopesStr;
}
using (HttpContent requestContent = new FormUrlEncodedContent(formData))
using (HttpRequestMessage request = CreateRequestMessage(HttpMethod.Post, _endpoints.DeviceAuthorizationEndpoint, requestContent))
using (HttpResponseMessage response = await _httpClient.SendAsync(request, ct))
View on GitHub (pinned to e8ce762cd0)