-
Notifications
You must be signed in to change notification settings - Fork 50
Description
Please provide us with the following information:
This issue is for a: (mark with an x)
- [x] bug report -> please search issues before submitting
- [ ] feature request
- [ ] documentation issue or request
- [ ] regression (a behavior that used to work and stopped in a new release)
Minimal steps to reproduce
Run the attached code. The response from httpClient.SendAsync(request) always returns Unauthorized
Any log messages given by the failure
None
Expected/desired behavior
Authorized!
OS and Version?
Windows 11 Home
Versions
10.0.26100
Mention any other details that might be useful
Unauthorized error:
{"error":{"code":"OrganizationFromTenantGuidNotFound","message":"The tenant for tenant guid '0ac2da02-f40e-4889-977c-67abc6b1ea17' does not exist.","innerError":{"oAuthEventOperationId":"be6f1ba5-ec8f-4bc1-8886-79677c609d98","oAuthEventcV":"dG+k3EExfgbY2xaPnR0BKA.1.1","errorUrl":"https://aka.ms/autherrors#error-InvalidTenant","requestId":"6646c447-ce81-4d17-b16a-38069494e270","date":"2025-01-11T23:47:34"}}}
The tenant ID is correctly set. I promise
I've correctly entered all GUIDs and verified 9 times. Authenticates fine. I have all mail permissions set to application scope and assigned by admin.
using Microsoft.Identity.Client;
using System.Net.Http.Headers;
using System.Text.Encodings.Web;
using System.Text.Json;
// based on https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-daemon-dotnet-acquire-token
// entra Tenant ID = 0ac2da02-f40e-4889-977c-67abc6b1ea17
// az portal Tenant ID = 0ac2da02-f40e-4889-977c-67abc6b1ea17
var tenantId = "00000000-f40e-4889-977c-67abc6b1ea17";
// entra Client ID = 0c29ca3a-0bcf-4861-8430-e5f47abf0972
// az portal Client ID = 0c29ca3a-0bcf-4861-8430-e5f47abf0972
var clientId = "11111111-0bcf-4861-8430-e5f47abf0972";
var clientSecret = "secret"; // the client secret obtained from the Microsoft Entra admin center",
// entra Client Object ID = 8e7c972c-289c-4fe2-b53e-a8a3dbe797cf (service principal ID - enterprise app)
// az portal Client Object ID = 088843fe-1ace-40d2-9c26-3f9a5a358a03
// not sure why I have two different Object ID's for the application but the azure portal one authenticates and the entra one does not
var clientObjectId = "22222222-1ace-40d2-9c26-3f9a5a358a03";
// entra User Object ID = 17142bbb-92cf-4c7d-b91b-d017534463d1
// az portal User Object ID = 17142bbb-92cf-4c7d-b91b-d017534463d1
var userId = "33333333-92cf-4c7d-b91b-d017534463d1";
var authority = $"https://login.microsoftonline.com/{tenantId}";
/**
* In Azure app permissions - these and many more:
* Mail.Read = Both Application and Delegated
* User.Read = Both Application and Delegated
* Mail.ReadWrite = Both Application and Delegated
* MailboxFolder.Read = Both Application and Delegated
* MailboxSettings.Read = Both Application and Delegated
* Mail.Read.Shared = Delegated
* Mail.Send = Both Application and Delegated
*/
// This app instance should be a long-lived instance because
// it maintains the in-memory token cache.
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithTenantId(tenantId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
// Acquire token for client credentials flow
var authenticationResult = await app.AcquireTokenForClient(["https://graph.microsoft.com/.default"]).ExecuteAsync();
var bearerToken = authenticationResult.AccessToken;
var httpClient = new HttpClient();
await Authenticate(httpClient, clientObjectId, bearerToken);
// At this point I have successful authentication
await GetMailboxesAsync(httpClient, bearerToken, clientObjectId); // <== this is where I get unauthorized
await SendEmailAsync(httpClient, userId, bearerToken); // <== this is where I get unauthorized
Console.ReadLine();
static async Task Authenticate(HttpClient httpClient, string clientObjectId, string bearerToken)
{
using var graphRequest = new HttpRequestMessage(HttpMethod.Get, $"https://graph.microsoft.com/v1.0/applications/{clientObjectId}");
graphRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
graphRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var graphResponseMessage = await httpClient.SendAsync(graphRequest);
if (graphResponseMessage.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
Console.WriteLine("Access denied. Please check the permissions granted to the application.");
return;
}
using var graphResponseJson = JsonDocument.Parse(await graphResponseMessage.Content.ReadAsStreamAsync());
Console.WriteLine(JsonSerializer.Serialize(graphResponseJson,
new JsonSerializerOptions { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }));
}
static async Task GetMailboxesAsync(HttpClient httpClient, string token, string userId)
{
// Call the GetMailboxes endpoint to get a list of mailboxes.
var getMailboxesRequest = new HttpRequestMessage(HttpMethod.Get, $"https://graph.microsoft.com/v1.0/users/{userId}/mailFolders");
getMailboxesRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var getMailboxesResponse = await httpClient.SendAsync(getMailboxesRequest);
if (getMailboxesResponse.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Console.WriteLine($"Access {getMailboxesResponse.StatusCode}. Why is this unauthorized?"); // <== this is where I get unauthorized
return;
}
if (!getMailboxesResponse.IsSuccessStatusCode)
{
Console.WriteLine($"Access {getMailboxesResponse.StatusCode}. ??");
return;
}
getMailboxesResponse.EnsureSuccessStatusCode();
// Parse the response to get a list of mailboxes.
var mailboxesJson = await getMailboxesResponse.Content.ReadAsStringAsync();
var mailboxes = JsonDocument.Parse(mailboxesJson).RootElement;
foreach (var mailbox in mailboxes.EnumerateArray())
{
Console.WriteLine(mailbox.GetProperty("displayName").GetString());
}
}
static async Task SendEmailAsync(HttpClient httpClient, string userId, string token)
{
var emailMessage = new
{
message = new
{
subject = "Test Email",
body = new
{
contentType = "Text",
content = "Hello, this is a test email!"
},
toRecipients = new[]
{
new
{
emailAddress = new
{
address = "wes.smith@outlook.com"
}
}
}
},
saveToSentItems = "true"
};
var requestContent = new StringContent(JsonSerializer.Serialize(emailMessage));
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var request = new HttpRequestMessage(HttpMethod.Post, $"https://graph.microsoft.com/v1.0/users/{userId}/sendMail")
{ Content = requestContent };
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Console.WriteLine($"Access {response.StatusCode}. Why is this unauthorized?"); // <== this is where I get unauthorized
return;
}
if (!response.IsSuccessStatusCode)
{
Console.WriteLine($"Access {response.StatusCode}. ??");
return;
}
Console.WriteLine(response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}