Events on Calendars in Microsoft Graph is always null? - azure

I'm trying to access the events of the users that shared their calendars with me. This is the code:
GraphServiceClient graphClient = new(new AzureAuthenticationProvider());
IUserCalendarsCollectionPage calendar = (
await graphClient.Me.Calendars
.Request()
.GetAsync()
);
public class AzureAuthenticationProvider : IAuthenticationProvider
{
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
var token = "bearer token";
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
}
I can access my Calendar and see my events but all the shared calendars that are shared with me have the Events property null:
I can access the shared calendars events using Postman and the collection is not empty, the issue is when I try to do this using the MS Graph library.
All the examples from Microsoft have bassically the same code as me so I'm not sure what the issue is.

Related

Microsft Graph API as WEB API application

I am banging my head for sometime now. I want to develop Web API which will be consume in my Angular APP. Purpose of API is to create/delete Microsoft Teams using Graph API.
I do have azure app with appropriate permission. and below is my code which keep giving me 403 error.
Can someone please help me ? also, do i have to apply permission to below option to access Grpah API without user interaction (as in Login Popup)
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("d78eaba6-12fe-8139")
.WithTenantId("fd49ee20-51a4-d930e2db05de")
.WithClientSecret("WTeN7A7-oeOfi~c9gF..")
.Build();
var scopes = new string[] { "https://graph.microsoft.com/.default" };
var authResult = await confidentialClientApplication.AcquireTokenForClient(scopes).ExecuteAsync();
string token = authResult.AccessToken;
await CallWebApiAndProcessResultASync("GET","https://graph.microsoft.com/v1.0/users", token, null, Display);
public static async Task CallWebApiAndProcessResultASync(string method,string webApiUrl, string accessToken, StringContent postValue, Action<JObject> processResult)
{
string request = string.Empty;
if (!string.IsNullOrEmpty(accessToken))
{
using (HttpClient HttpClient = new HttpClient())
{
var defaultRequestHeaders = HttpClient.DefaultRequestHeaders;
if (defaultRequestHeaders.Accept == null || !defaultRequestHeaders.Accept.Any(m => m.MediaType == "application/json"))
{
HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
defaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
using (HttpRequestMessage httpRequestMessage = new HttpRequestMessage(new HttpMethod(method), webApiUrl) { Content = postValue })
{
var response = HttpClient.SendAsync(httpRequestMessage).Result;
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
JObject result = JsonConvert.DeserializeObject(json) as JObject;
Console.ForegroundColor = ConsoleColor.Gray;
processResult(result);
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Failed to call the Web Api: {response.StatusCode}");
string content = await response.Content.ReadAsStringAsync();
// Note that if you got reponse.Code == 403 and reponse.content.code == "Authorization_RequestDenied"
// this is because the tenant admin as not granted consent for the application to call the Web API
Console.WriteLine($"Content: {content}");
}
}
Console.ResetColor();
}
}
}
Yes, if you don’t need user interaction, you just need to grant application permissions for your application, and grant admin consent for the permissions you added. If you need to call MS Graph API to create/delete Microsoft Teams, please grant your application Directory.ReadWrite.All permission.

How do I Call Microsoft Teams OnlineMeeting endpoints via Microsoft Graph API using a console app?

I have followed the code example given in the following link by Microsoft and was successfully able to get the list of users.
My registered app in the Azure Active Directory also have the "OnlineMeeting.ReadWrite.All" application permission.
But when I am trying to call the create meeting call by posting the request in the endpoint "https://graph.microsoft.com/v1.0/me/onlineMeetings". I am getting a 403 forbidden error. Any idea why I am getting this?
For the graph api create online meetings https://graph.microsoft.com/v1.0/me/onlineMeetings, we can see the tutorial shows it doesn't support "Application permission" to call it. It just support "Delegated permission", so we can just request it by password grant flow but not client credential flow.
Update:
For your requirement to request the graph api of creating online meeting, we can just use password grant flow or auth code flow. Here provide a sample of password grant flow(username and password) for your reference, use this sample to get the token and request the graph api by this token. You can also find this sample in this tutorial.
static async Task GetATokenForGraph()
{
string authority = "https://login.microsoftonline.com/contoso.com";
string[] scopes = new string[] { "user.read" };
IPublicClientApplication app;
app = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(authority)
.Build();
var accounts = await app.GetAccountsAsync();
AuthenticationResult result = null;
if (accounts.Any())
{
result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
else
{
try
{
var securePassword = new SecureString();
foreach (char c in "dummy") // you should fetch the password
securePassword.AppendChar(c); // keystroke by keystroke
result = await app.AcquireTokenByUsernamePassword(scopes,
"joe#contoso.com",
securePassword)
.ExecuteAsync();
}
catch(MsalException)
{
// See details below
}
}
Console.WriteLine(result.Account.Username);
}

Facing "The token contains no permissions, or permissions can not be understood." issue in EWS with Oauth

We have requirement in which we need to add appointment to user outlook account on behalf of that user using delegate access. All mails are in same domain or same network. We are trying this by using Oauth with office365, by creating Azure application and providing application level "calendar read and write" delegate permission.
I have referred https://blogs.msdn.microsoft.com/exchangedev/2015/01/21/building-daemon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow/ article to setup azure application, which will provide me a access token.
While fetching access token I have used following code
private static string GetTokenUsingCertificate()
{
string authority = string.Format("https://login.windows.net/{0}/oauth2/authorize", tenantID); ;
string outlookUri = "https://outlook.office365.com/";
var authenticationContext = new AuthenticationContext(authority, false);
var clientCertificate = new ClientAssertionCertificate(clientId, GetClientCertificate());
AuthenticationResult authenticationResult = null;
try
{
authenticationResult = authenticationContext.AcquireTokenAsync(outlookUri, clientCertificate).Result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return authenticationResult?.AccessToken;
}
above function is providing me access token but when I try to add appointment to user outlook calendar using Exchnage Service, I am getting "The token contains no permissions, or permissions can not be understood." exception.
While adding appointment I am using following code
private void AddAppointment()
{
ExchangeService exchangeService = new ExchangeService();
exchangeService.Credentials = new OAuthCredentials(accessToken);
exchangeService.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
Appointment appointment = new Appointment(service)
{
Subject = "EWS OAuth: Appointment 2",
Body = "EWS OAuth Auth: Body",
Start = DateTime.Now.AddMinutes(10)
};
appointment.Save(
new FolderId(WellKnownFolderName.Calendar, new Mailbox("mail#outlook.com/")),
SendInvitationsMode.SendToNone);
}
Please help me to resolve this issue.
Blockquote
EWS doesn't allow the same level of OAuth permissions scope (or permission restriction) that the REST API allows for which is one of the big benefit of using REST vs EWS. If you have Office365 why are trying to use EWS over REST ?
To answer the question you will need
OAuth authentication for EWS is only available in Exchange as part of Office 365. EWS applications require the "Full access to user's mailbox" permission.
as per https://msdn.microsoft.com/en-us/library/office/dn903761%28v=exchg.150%29.aspx .

Create custom extension through Graph API with Client Credentials auth

I have a .NET Web API that I am using to do some interaction with Microsoft Graph and Azure AD. However, when I attempt to create an extension on the user, it comes back with Access Denied.
I know it is possible from the documentation here however, it doesnt seem to work for me.
For the API, I am using client credentials. So my web app authenticates to the API using user credentials, and then from the API to the graph it uses the client.
My app on Azure AD has the Application Permission Read and Write Directory Data set to true as it states it needs to be in the documentation for a user extension.
I know my token is valid as I can retrieve data with it.
Here is my code for retrieving it:
private const string _createApprovalUrl = "https://graph.microsoft.com/beta/users/{0}/extensions";
public static async Task<bool> CreateApprovalSystemSchema(string userId)
{
using(var client = new HttpClient())
{
using(var req = new HttpRequestMessage(HttpMethod.Post, _createApprovalUrl))
{
var token = await GetToken();
req.Headers.Add("Authorization", string.Format("Bearer {0}", token));
req.Headers.TryAddWithoutValidation("Content-Type", "application/json");
var requestContent = JsonConvert.SerializeObject(new { extensionName = "<name>", id = "<id>", approvalLimit = "0" });
req.Content = new StringContent(requestContent, Encoding.UTF8, "application/json");
using(var response = await client.SendAsync(req))
{
var content = await response.Content.ReadAsStringAsync();
ApprovalSystemSchema schema = JsonConvert.DeserializeObject<ApprovalSystemSchema>(content);
if(schema.Id == null)
{
return false;
}
return true;
}
}
}
}
Is there anyone who may have a workaround on this, or information as to when this will be doable?
Thanks,
We took a look and it looks like you have a bug/line of code missing. You appear to be making this exact request:
POST https://graph.microsoft.com/beta/users/{0}/extensions
Looks like you are missing the code to replace the {0} with an actual user id. Please make the fix and let us know if you are now able to create an extension on the user.

Is it possible to operate OneNote with azure daemon App?

In order to operate OneNote with azure's daemon app,
I created a new ClientID, acquired the Access Token by user authentication with that ClientID, and realized access to the OneNote API using it.
However, instead of user authentication, Access token is acquired by ClientID and certificate, and access to OneNote API using it is refused.(401 Unauthorized)
How can I operate OneNote from azure dameon App?
The way I tried
The AccessToken creation by the certificate was implemented with reference to the following.
https://azure.microsoft.com/ja-jp/resources/samples/active-directory-dotnet-daemon-certificate-credential/
Specific AccessToken acquisition codes are as follows,
public async Task AuthWithCertAsync(string tenant, string clientID, string certName)
{
var authority = $"{aadInstance}{tenant}";
var authContext = new AuthenticationContext(authority);
//refer: above URL
ClientAssertionCertificate certCred = GetCertificate(clientID, certName);
if (certCred == null) {return false;}
//"https://graph.microsoft.com/";
var graphResult = await authContext.AcquireTokenAsync(graphResourceID, certCred);
graphToken = graphResult.AccessToken;
//"https://www.onenote.com/";
var onenoteResult = await authContext.AcquireTokenAsync(onenoteResourceID, certCred);
onenoteToken = onenoteResult.AccessToken;
}
With this graphToken, access to the Graph API succeeds.
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {graphToken}");
//e.g. "https://graph.microsoft.com/v1.0/groups", "https://graph.microsoft.com/v1.0/users"
var response = await client.GetStringAsync(url);
...
}
However, if the target URL is an API on onenote, it fails.
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {graphToken}");
//e.g:"https://graph.microsoft.com/beta/users/{userID}/notes/notebooks"
// Occured HttpRequestException(401 Unauthorized)
var response = await client.GetStringAsync(url);
...
}
This request returns HTTP 401 Unauthorized status.
Also when accessing OneNote API on onenoteToken failed.
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {onenoteToken}");
//e.g.:"https://www.onenote.com/api/v1.0/users/{userID}/notes/notebooks"
var response = await client.GetStringAsync(url);
return response;
}
This request also returns HTTP 401 Unauthorized status.
The application setting in Azure Active Directory:
Type:
WEB APPLICATION AND/OR WEB API
Multi Tenant:
ON
permissions to other applications:
Graph, OneNote, Active Directory, SharePoint :Application Permissions all checked.
In the admin account of the target tenant, the following admin consent URL is accessed and accepted.
https://login.microsoftonline.com/common/adminconsent?client_id={clientID}&state={state}&redirect_uri={redirectUrl}
Update
According to the answer of https://stackoverflow.com/a/41890179/1411521,
I understood that there is no way to access OneNote by daemon App with the current Graph API. (at 2017-1-31)
However, Application Permission of OneNote API can set as follows.
View and modify notes for all users
View notes for all users
Despite the fact that they are valid, what causes the authentication error (401 Unauthorized) with the following code?
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {onenoteToken}");
//e.g.:"https://www.onenote.com/api/v1.0/users/{userID}/notes/notebooks"
var response = await client.GetStringAsync(url); // Occured HttpRequestException(401 Unauthorized)
...
}
You were mixing the Microsoft Graph and OneNote API.
The token you were acquire is for the Microsoft Graph REST, and you can manipulate the OnenNote through Microsoft Graph REST which in beta version by following the document here(beta reference->OneNote).
And if you want to use the OneNoe API, you can refer the document here for the authentication.
Update
To list the notebooks, we need permissions like Notes.Read, Notes.ReadWrite.CreatedByApp, Notes.ReadWrite, Notes.Read.All, or Notes.ReadWrite.All. However there is no such kinds of permission for the Client Credential flow for Microsoft Graph.
If you want the Microsoft Graph to support the Client Credential flow to manipulate the OneNote, you can submit the feedback from here.
This problem was solved today(2017-2-10).
The OneNote REST API now supports application-level permissions
OneNote authentication and Azure AD application permissions

Resources