💻

Microsoft Graph で会議室の予定表を取得する

2022/01/01に公開

元ネタはこちらです。

https://social.msdn.microsoft.com/Forums/ja-JP/2c124c80-585b-426f-94ed-68131049e954?WT.mc_id=M365-MVP-5002941

OAuth を使ったアプリケーションで「アクセス許可を与えたのにデータが取れない」という状況が発生するということをよく耳にします。

上記の「Calendars.ReadWrite.Shared を付けたのに会議室の情報が取れない」というのは、アプリを使用するユーザーに権限がないからです。これはむしろ正しい動作といえます。委任されたアクセス許可 という名前が表す通りですね。

Microsoft のドキュメントにも説明があります。

https://developer.microsoft.com/ja-jp/graph/docs/concepts/permissions_reference?WT.mc_id=M365-MVP-5002941

委任されたアクセス許可の場合、アプリの有効なアクセス許可は、アプリに付与されている委任されたアクセス許可 (同意によって付与) と現在サインインしているユーザーの特権が重なる範囲に収まる最小権限になります。

対応方法としては アプリケーションのアクセス許可 を使うことになります。ただし、こちらは、バックグラウンドで動作するアプリケーションを想定しているので、気を付けなければなりません。たとえば、アクセス許可に Calendars.Read を付けると、特定のアカウントだけではなく、すべてのアカウントの予定表が見られるようになります。これはセキュリティ上のリスクが高くなるので、フロントエンドで動作するアプリでの使用は特に気を付けなければなりません。

前置きが長くなったのでサンプル コードです。今回は MSAL を使っています。

using Microsoft.Identity.Client;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace ConsoleApplication1
{

    public static class Program
    {

        private static readonly string TenantId = "{{tenant-id}}";
        private static readonly string RedirectUrl = "{{redirect-url}}";
        private static readonly string ClientId = "{{client-id}}";
        private static readonly string ClientSecret = "{{client-secret}}";

        private static readonly string Authority = $"https://login.microsoftonline.com/{TenantId}/v2.0";
        private static readonly string ResourceId = "https://graph.microsoft.com/.default";
        private static readonly string RequestUrl = "https://graph.microsoft.com/v1.0/users/{0}/calendarView?StartDateTime={1:s}&EndDateTime={2:s}";

        private static void Main(string[] args)
        {
            var userId = "{{resource-id}}";
            var startDateTime = DateTime.Today;
            var endDateTime = DateTime.Today.AddDays(1);
            GetCalendarAsync(userId, startDateTime, endDateTime).GetAwaiter().GetResult();
        }

        private static async Task GetCalendarAsync(string userId, DateTime startDateTime, DateTime endDateTime)
        {
            var oauthClient = new ConfidentialClientApplication(ClientId, Authority, RedirectUrl, new ClientCredential(ClientSecret), null, new TokenCache());
            var oauthResult = await oauthClient.AcquireTokenForClientAsync(new[] { ResourceId });
            var httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", oauthResult.AccessToken);
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var responseMessage = await httpClient.GetAsync(string.Format(RequestUrl, userId, startDateTime, endDateTime));
            var responseContent = await responseMessage.Content.ReadAsStringAsync();
        }

    }

}

ちなみに、findMeetingTimesアプリケーションのアクセス許可 では動作しないので、こちらを使いたい場合はメールボックスにアクセス許可を付けるしかありません。

Discussion