Search code examples
c#azuremicrosoft-graph-apiasp.net-core-webapi

Error when creating a MS Teams meeting using Microsoft Graph API in an ASP.NET Web API in C#


I am currently developing an ASP.NET Web API that will enable the creation of Teams meetings and the retrieval of the connection URL. I have followed Microsoft's documentation, but it seems incomplete, and I am encountering numerous errors.

I added an app registration in Azure with the API permissions OnlineMeetings.ReadWrite.All. I should be able to create multiple links simultaneously without using a generic account. I simply want to authorize my resource to create meetings.

var tenantId = "...";
var clientId = "...";
var clientSecret = "...";

var options = new TokenCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};

var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret, options);

var graphClient = new GraphServiceClient(clientSecretCredential);

var requestBody = new Microsoft.Graph.Users.Item.OnlineMeetings.CreateOrGet.CreateOrGetPostRequestBody
{
    StartDateTime = DateTimeOffset.Parse("2024-02-20T14:30:00.2444915-07:00"),
    EndDateTime = DateTimeOffset.Parse("2024-02-20T15:00:00.2464912-07:00"),
    Subject = "Test meeting from graph API",
    Participants = new MeetingParticipants
    {
        Organizer = new MeetingParticipantInfo
        {
            Identity = new IdentitySet
            {
                User = new Identity
                {
                    Id = "[email protected]"
                }
            },
            Upn = "[email protected]"
        },
        Attendees = new List<MeetingParticipantInfo>
        {
            new MeetingParticipantInfo
            {
                Identity = new IdentitySet
                {
                    User = new Identity
                    {
                        Id = "[email protected]"
                    }
                },
                Upn = "[email protected]"
            }
        }
    }
};

var result = await graphClient.Users["[email protected]"].OnlineMeetings.CreateOrGet.PostAsync(requestBody);
return result.JoinWebUrl;

When executing this code with the specified credentials from Azure, I am getting this error:

Microsoft.Graph.Models.ODataErrors.ODataError

with an http 404 error code

This exception was originally thrown at this call stack:

Library.Http.HttpClientRequestAdapter.ThrowIfFailedResponse(System.Net.Http.HttpResponseMessage, System.Collections.Generic.Dictionary<string, Library.Abstractions.Serialization.ParsableFactory<Library.Abstractions.Serialization.IParsable>>, System.Diagnostics.Activity, System.Threading.CancellationToken)
Library.Http.HttpClientRequestAdapter.SendAsync(Library.Abstractions.RequestInformation, Library.Abstractions.Serialization.ParsableFactory, System.Collections.Generic.Dictionary<string, Library.Abstractions.Serialization.ParsableFactory<Library.Abstractions.Serialization.IParsable>>, System.Threading.CancellationToken)
Library.Http.HttpClientRequestAdapter.SendAsync(Library.Abstractions.RequestInformation, Library.Abstractions.Serialization.ParsableFactory, System.Collections.Generic.Dictionary<string, Library.Abstractions.Serialization.ParsableFactory<Library.Abstractions.Serialization.IParsable>>, System.Threading.CancellationToken)
Users.Item.OnlineMeetings.CreateOrGet.CreateOrGetRequestBuilder.PostAsync(Users.Item.OnlineMeetings.CreateOrGet.CreateOrGetPostRequestBody, System.Action<Library.Abstractions.RequestConfiguration<Library.Abstractions.DefaultQueryParameters>>, System.Threading.CancellationToken) in CreateOrGetRequestBuilder.cs
App.Services.MeetingGeneratorService.CreateMeeting(App.Dto.v2.MeetingDto) in MeetingGeneratorService.cs


Solution

  • According to your code graphClient.Users["[email protected]"].OnlineMeetings, it looks like you are trying to use this API to create teams meeting. Then let's see the permission information in the API document, it indicates that Application type of permission is not supported, which means we aren't able to use client credential flow to generate access token(requires Application type of permission) then call this API. However, we can see that you are using client credential flow in your codes -> var clientSecretCredential = new ClientSecretCredential

    As a workaround, we can use Calendar events API as to create online meetings which supports Application type of permission. Setting IsOnlineMeeting = true and adding Application type permission Calendars.ReadWrite are required. I had a test before to prove this API can solve your problem. Code snippet should look like below.

    // Code snippets are only available for the latest version. Current version is 5.x
    using Microsoft.Graph.Models;
    using Microsoft.Graph;
    using Azure.Identity;
    
    var requestBody = new Event
    {
        Subject = "Let's go for lunch",
        Body = new ItemBody
        {
            ContentType = BodyType.Html,
            Content = "Does next month work for you?",
        },
        Start = new DateTimeTimeZone
        {
            DateTime = "2019-03-10T12:00:00",
            TimeZone = "Pacific Standard Time",
        },
        End = new DateTimeTimeZone
        {
            DateTime = "2019-03-10T14:00:00",
            TimeZone = "Pacific Standard Time",
        },
        Location = new Location
        {
            DisplayName = "Harry's Bar",
        },
        Attendees = new List<Attendee>
        {
            new Attendee
            {
                EmailAddress = new EmailAddress
                {
                    Address = "[email protected]",
                    Name = "Adele Vance",
                },
                Type = AttendeeType.Required,
            },
        },
        IsOnlineMeeting = true,
        OnlineMeetingProvider = OnlineMeetingProviderType.TeamsForBusiness,
    };
    
    var scopes = new[] { "https://graph.microsoft.com/.default" };
    var tenantId = "tenantId";
    var clientId = "clientId";
    var clientSecret = "clientSecret";
    var clientSecretCredential = new ClientSecretCredential(
                    tenantId, clientId, clientSecret);
    var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
    var result = await graphClient.Users["{user_id}"].Events.PostAsync(requestBody);