E Vakhovsky
E Vakhovsky

Reputation: 44

Can't call Graph API calendars from a daemon application

I am new to the Graph API and would like to call my outlook calendars with the event schedules from a daemon application.

When I login to Microsoft account using the email I use to login to Azure I can see my calendar fine and I can also call the Web API using the Graph Explorer.

E.g. the Graph Explorer call:

https://graph.microsoft.com/v1.0/me/calendars

returns my calendar events fine when I am logged in with my Microsoft account.

Now, I would like to be able to access the same API using a service application i.e. without the user login prompt. So I went to the Azure portal, created and registered a new application, gave it Calendar.Read API permission with the administrator's consent and downloaded a quickstart daemon app which makes

await apiCaller.CallWebApiAndProcessResultASync($"{config.ApiUrl}v1.0/users", result.AccessToken, Display);

call which works i.e. it returns a user so that I can see that the

"userPrincipalName": "XYZ@<formattedemail>.onmicrosoft.com"

which is not what the Graph Explorer call returns. The Graph explorer call:

https://graph.microsoft.com/v1.0/users

and returns "userPrincipalName": "myactualemail"

So basically when I make the Graph Explorer call:

https://graph.microsoft.com/v1.0/me/calendars

it returns the calendars' result which is correct.

However, an equivalent daemon API call

await apiCaller.CallWebApiAndProcessResultASync($"{config.ApiUrl}v1.0/users/f5a1a942-f9e4-460b-9c6c-16f45045548f/calendars", result.AccessToken, Display);

returns:

Failed to call the web API: NotFound

Content: {"error":{"code":"ResourceNotFound","message":"Resource could not be discovered.","innerError":{"date":"2021-12-26T16:46:35","request-id":"67ef50e4-bec6-48ae-9e45-7765436d1345","client-request-id":"67ef50e4-bec6-48ae-9e45-7765436d1345"}}}

I suspect that the issue is in the userPrincipalName mismatch between the Graph Explorer and the daemon application, but I am failing to find a solution to this.

Also note that a normal ASP.NET Core sample which requires manual user login works ok. The issue is only with the daemon application.

Upvotes: 1

Views: 512

Answers (3)

E Vakhovsky
E Vakhovsky

Reputation: 44

I was able to kind of resolve this issue after chatting with the Azure tech guy. It turned out that my Azure account was considered a personal account. And the reason for this apparently was because I was using a personal @yahoo.com email to setup up the Azure account first place. Because of this they would apparently not allow me to purchase o365 and license it. So I had to create a new account with the amazon default domain for S3 - awsapps.com, which I took from my AWS S3 subscription. Then I had to run through a whole process of creating a new email in Azure from my existing S3 custom domain. After the email was created I was able to purchase o365 basic license (trial version for now) and then login to Azure using a new email. o365 purchase gave me access to outlook and then recreating a new daemon application from the quickstart with the new credentials just worked. I don't know if it makes sense what I had done as it sounds awfully convoluted. But it seems to work in the end.

Upvotes: 0

Tiny Wang
Tiny Wang

Reputation: 15906

When you used Graph Explorer to test the api, you've signed in the website, so /me/calendars contained in the request can know who is me and then return correct data to you.

Come back to your daemon app, we usually use client credential flow to gain the access token/credential to call the api in the daemon so that we don't need to let user sign in and then call the api, this flow makes the app itself can call microsoft graph api. But using this flow will lead to the issue that you can't use me any more because you never signed in yourself, so we should use /users/userPrincipalName/calendars instead.

Then come to the programming module, microsoft provides graph SDK for calling api, this is what you can also see in the api document. You can refer to this document to learn more details about how to use client credential flow with graph SDK. You can also copy my code below.

using Azure.Identity;
using Microsoft.Graph;

public IActionResult Privacy()
{
    var scopes = new[] { "https://graph.microsoft.com/.default" };
    var tenantId = "your_tenant_name.onmicrosoft.com";
    var clientId = "azure_ad_app_client_id";
    var clientSecret = "client_secret";
    var options = new TokenCredentialOptions
    {
        AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
    };
    var clientSecretCredential = new ClientSecretCredential(
        tenantId, clientId, clientSecret, options);
    var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
    var res = graphClient.Users["your_user_id_which_looks_like_xxxx-xxx-xxx-xxxx-xxxxxx"].Calendars.Request().GetAsync().Result;
    return View();
} 

enter image description here

By the way, if you're not familiar with the flows, you may take a look at my this answer.

Upvotes: 0

Dmitry Streblechenko
Dmitry Streblechenko

Reputation: 66215

There is no "me" in your case, so you need to use https://graph.microsoft.com/v1.0/users/[email protected]/calendars url.

Upvotes: 0

Related Questions