I'm building a service in .NET 6 to interact with Azure DevOps APIs, but I continually get an 401 Unauthorized response on my single method. My personal access token does work when I run this through Powershell. And my EncodeToken method seems to work. Any ideas on why this blows up?
public class ADOService
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _config;
private readonly string _token;
private readonly string _rootUrl;
private readonly string _project;
public ADOService(IConfiguration configuration)
{
_config = configuration;
_httpClient = new HttpClient();
_token = _config.GetSection("AzureDevOpsApiSettings").GetValue<string>("ADOPersonalAccessToken");
_rootUrl = _config.GetSection("AzureDevOpsApiSettings").GetValue<string>("ADORootUrl");
_project = _config.GetSection("AzureDevOpsApiSettings").GetValue<string>("Project");
if (string.IsNullOrEmpty(_token) || string.IsNullOrEmpty(_rootUrl) || string.IsNullOrEmpty(_project))
{
throw new Exception("ADO Service is not properly configured");
}
}
public async Task<ExpandoObject> GetWorkItems()
{
SetHttpHeaders();
HttpResponseMessage response = await _httpClient.GetAsync($"{_project}/_apis/wit/workitemsbatch?api-version=6.0");
if (!response.IsSuccessStatusCode)
{
throw new ApplicationException("failed");
}
else
{
var content = await response.Content.ReadAsStringAsync();
var workItems = JsonSerializer.Deserialize<ExpandoObject>(content);
return workItems;
}
}
private string EncodeToken(string token)
{
if (string.IsNullOrEmpty(token)) throw new ArgumentNullException("token");
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(token);
return Convert.ToBase64String(plainTextBytes);
}
private void SetHttpHeaders()
{
_httpClient.BaseAddress = new Uri(_rootUrl);
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", EncodeToken(_token));
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
}
CodePudding user response:
Looks like your PAT is not converted to a valid Base64 string.
You can reference the example here to change your code to convert the PAT to a Base64 string and add it to the request header.
public static async void GetProjects()
{
try
{
var personalaccesstoken = "PAT_FROM_WEBSITE";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", personalaccesstoken))));
using (HttpResponseMessage response = await client.GetAsync(
"https://dev.azure.com/{organization}/_apis/projects"))
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}