如何解决C#调用Azure AD获取AccessToken时的AADSTS900144错误?
解决AADSTS900144错误:获取Azure AD访问令牌失败问题
错误详情
{ "error": "invalid_request", "error_description": "AADSTS900144: The request body must contain the following parameter: 'grant_type'.\r\nTrace ID: e605b59b-ce96-443a-be34-a80c00b84f00\r\nCorrelation ID: d6a891a8-4aed-485c-939d-95a377ca1c3d\r\nTimestamp: 2023-07-21 11:14:38Z", "error_codes": [ 900144 ], "timestamp": "2023-07-21 11:14:38Z", "trace_id": "e605b59b-ce96-443a-be34-a80c00b84f00", "correlation_id": "d6a891a8-4aed-485c-939d-95a377ca1c3d", "error_uri": "https://login.microsoftonline.com/error?code=900144" }
原问题代码
private static async Task<string> GetAccessTokenAsync(string tenantId, string azureClientId, string code, string azureRedirectURI, string azureResourceURI) { using (var httpClient = new HttpClient()) { var tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token"; var requestBody = $"grant_type=authorization_code&client_id={azureClientId}&code={code}&redirect_uri={azureRedirectURI}&resource={azureResourceURI}"; var content = new StringContent(requestBody, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded"); var response = await httpClient.PostAsync(tokenEndpoint, content); if (response.IsSuccessStatusCode) { var responseContent = await response.Content.ReadAsStringAsync(); // Assuming the response contains a JSON string // You may want to use a JSON serializer to deserialize the responseContent. // For simplicity, we're assuming it's a JSON string. // You can use NewtonSoft.Json.JsonConvert.DeserializeObject to deserialize the JSON. return responseContent; } else { // Handle the error if needed // You can check response.StatusCode and response.ReasonPhrase for more details. throw new Exception($"Request failed with status code: {response.StatusCode}, Reason: {response.ReasonPhrase}"); } } }
问题分析
AADSTS900144错误提示请求体缺少grant_type参数,但代码中已明确拼接该参数,大概率是手动拼接请求体时的编码问题:如果参数(如授权码code)包含特殊字符(如&、=、+等),会破坏表单参数的结构,导致Azure AD服务器无法正确解析出grant_type参数。
另外,StringContent虽然指定了application/x-www-form-urlencoded类型,但不会自动对参数进行URL编码,这也是导致参数解析失败的常见原因。
代码修复方案
改用FormUrlEncodedContent构建请求体,它会自动处理参数的URL编码,避免手动拼接的错误:
private static async Task<string> GetAccessTokenAsync(string tenantId, string azureClientId, string code, string azureRedirectURI, string azureResourceURI) { using (var httpClient = new HttpClient()) { var tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token"; // 使用字典组织参数,自动处理URL编码 var formData = new Dictionary<string, string> { ["grant_type"] = "authorization_code", ["client_id"] = azureClientId, ["code"] = code, ["redirect_uri"] = azureRedirectURI, ["resource"] = azureResourceURI }; var content = new FormUrlEncodedContent(formData); var response = await httpClient.PostAsync(tokenEndpoint, content); if (response.IsSuccessStatusCode) { var responseContent = await response.Content.ReadAsStringAsync(); // 建议使用JSON序列化库(如Newtonsoft.Json或System.Text.Json)解析响应 // 示例:var tokenResult = JsonConvert.DeserializeObject<TokenResponse>(responseContent); return responseContent; } else { // 捕获错误响应内容,便于排查问题 var errorContent = await response.Content.ReadAsStringAsync(); throw new Exception($"请求失败,状态码: {response.StatusCode},错误详情: {errorContent}"); } } } // 可选:定义TokenResponse类用于解析响应 // public class TokenResponse // { // [JsonProperty("access_token")] // public string AccessToken { get; set; } // [JsonProperty("token_type")] // public string TokenType { get; set; } // [JsonProperty("expires_in")] // public int ExpiresIn { get; set; } // }
运行代码前的前置检查
- 确认Azure AD应用注册的**客户端ID(azureClientId)和租户ID(tenantId)**完全正确,无拼写或格式错误
- 验证**重定向URI(azureRedirectURI)**与应用注册中配置的重定向URI完全一致,包括协议(HTTP/HTTPS)、域名和路径
- 确保授权码
code有效:未过期(默认有效期10分钟)、与当前客户端ID和重定向URI匹配,且未被使用过(授权码仅可使用一次) - 确认**资源URI(azureResourceURI)**正确对应AVD服务,通常为
https://rdweb.wvd.microsoft.com - 检查应用注册是否已配置AVD相关的API权限(如
Windows Virtual Desktop的权限),必要时完成管理员同意 - 确认令牌端点无误:授权码流程的端点为
https://login.microsoftonline.com/{tenantId}/oauth2/token,确保租户ID替换正确
内容的提问来源于stack exchange,提问作者Sangeetha
相关产品推荐
相关产品推荐

