I'm trying to retrieve Exchange Audit logs using manage.office.com endpoint.
This is the code:
public class ExchangeAuditLogReaderHelper
{
private readonly string _tenantId;
private readonly string _clientId;
private readonly string _clientSecret;
private readonly string _apiUrl = "https://manage.office.com/api/v1.0/{0}/activity/feed/subscriptions/content?contentType=Audit.Exchange&startTime={1:yyyy-MM-dd'T'HH:mm:ss}&endTime={2:yyyy-MM-dd'T'HH:mm:ss}";
public ExchangeAuditLogReaderHelper(string tenantId, string clientId, string clientSecret)
{
_tenantId = tenantId;
_clientId = clientId;
_clientSecret = clientSecret;
}
public async Task<string> GetAuditLogsAsync(DateTime startTime, DateTime endTime)
{
var accessToken = await GetAccessToken();
var url = string.Format(_apiUrl, _tenantId, startTime, endTime);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var contentString = await response.Content.ReadAsStringAsync();
// Parse the JSON response and extract audit log entries (implementation omitted)
return contentString;
}
else
{
throw new Exception($"Error retrieving audit logs: {response.StatusCode}");
}
}
}
private async Task<string> GetAccessToken()
{
var authority = $"https://login.microsoftonline.com/{_tenantId}";
var authenticationContext = new AuthenticationContext(authority);
var clientCredential = new ClientCredential(_clientId, _clientSecret);
var userAssertion = await authenticationContext.AcquireTokenAsync("https://manage.office.com", clientCredential);
return userAssertion.AccessToken;
}
}
I have done the following steps:
I ran code with the values I have created, but I'm getting 401. Am I missing permissions for this?
The error might occur if you granted permissions of Delegated type that won't work with app-only flow.
Initially, I too got same error when I granted Delegated permissions in the application and tried to call API like this:
When I decoded this access token in jwt.ms, it does not have roles
claim in it:
To resolve the error, make sure to grant permissions of Application type while using app-only flows:
When I ran below code after granting permissions of Application type, I got the response (blank as I don't have any):
using System.Net.Http.Headers;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
public class ExchangeAuditLogReaderHelper
{
private readonly string _tenantId;
private readonly string _clientId;
private readonly string _clientSecret;
private readonly string _apiUrl = "https://manage.office.com/api/v1.0/{0}/activity/feed/subscriptions/content?contentType=Audit.Exchange&startTime={1:yyyy-MM-dd'T'HH:mm:ss}&endTime={2:yyyy-MM-dd'T'HH:mm:ss}";
public ExchangeAuditLogReaderHelper(string tenantId, string clientId, string clientSecret)
{
_tenantId = tenantId;
_clientId = clientId;
_clientSecret = clientSecret;
}
public async Task<string> GetAuditLogsAsync(DateTime startTime, DateTime endTime)
{
var accessToken = await GetAccessToken();
var url = string.Format(_apiUrl, _tenantId, startTime, endTime);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var contentString = await response.Content.ReadAsStringAsync();
return contentString;
}
else
{
var statusCode = (int)response.StatusCode;
var errorMessage = await response.Content.ReadAsStringAsync();
throw new Exception($"Error retrieving audit logs. Status code: {statusCode}. Error Message: {errorMessage}");
}
}
}
private async Task<string> GetAccessToken()
{
var authority = $"https://login.microsoftonline.com/{_tenantId}";
var authenticationContext = new AuthenticationContext(authority);
var clientCredential = new ClientCredential(_clientId, _clientSecret);
var userAssertion = await authenticationContext.AcquireTokenAsync("https://manage.office.com", clientCredential);
// Print the access token to the console
Console.WriteLine("Access Token: " + userAssertion.AccessToken);
return userAssertion.AccessToken;
}
}
class Program
{
static async Task Main(string[] args)
{
// Replace these with your actual values
var tenantId = "tenantId";
var clientId = "appId";
var clientSecret = "secret";
var helper = new ExchangeAuditLogReaderHelper(tenantId, clientId, clientSecret);
// Specify start and end time as required
var startTime = DateTime.UtcNow.AddDays(-1);
var endTime = DateTime.UtcNow;
try
{
var logs = await helper.GetAuditLogsAsync(startTime, endTime);
Console.WriteLine(logs);
}
catch (Exception ex)
{
Console.WriteLine($"\n{ex.Message}");
}
}
}
Response:
You can also decode this access token in jwt.ms and check for roles
claim value to know what permissions token have: