Adding a Teams Channel Using MS Graph - c#

I am trying to create a channel using MS Graph within a BotFramework bot. I get what appears to be a valid access Token. However the code below generates the following error:
The collection type 'Microsoft.Graph.IChannelMembersCollectionPage' on 'Microsoft.Graph.Channel.Members' is not supported.
var credential = new DefaultAzureCredential();
var token = credential.GetToken(
new Azure.Core.TokenRequestContext(
new[] { "https://graph.microsoft.com/.default" }));
var accessToken = token.Token;
Logger.LogWarning($"Token:{accessToken.ToString()}");
var graphServiceClient = new GraphServiceClient(
new DelegateAuthenticationProvider((requestMessage) =>
{
requestMessage
.Headers
.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
return Task.CompletedTask;
}));
try
{
var chan = new Channel
{
DisplayName = $"Chan1",
Description = "This channel is where we debate all future world domination plans",
MembershipType = ChannelMembershipType.Standard
};
await graphServiceClient.Teams["{GroupID}"].Channels.Request().AddAsync(chan);
}

You can use Graph SDK to generate token internally. Please try providing application permissions in azure portal and use the below code to create a channel in MS Teams. Below are the packages you need to install.
This is an example for application permissions. You can try the same code with minor changes/to no changes for delegate permissions.
string clientId = "";
string clientSecret = "1";
string tenantId = "";
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.WithClientSecret(clientSecret) // or .WithCertificate(certificate)
.Build();
//AuthorizationCodeProvider authProvider = new AuthorizationCodeProvider(confidentialClientApplication, scopes);
ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var channel = new Channel
{
DisplayName = "Topic Discussion",
Description = "This channel is where we debate all future architecture plans",
MembershipType = ChannelMembershipType.Standard
};
await graphClient.Teams["{Your-teams-id}"].Channels
.Request()
.AddAsync(channel);

Related

how to read email attachment using microsoft graph api with delegate permissions in C# Web Form

I am new to Microsoft Graph API. My requirement is to read all emails attachment and insert them into SQL Database. My client is allowing only delegate permission to implement this requirement. I follow the below-mentioned code but it is neither showing me any error or any result.
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "azure_ad_appid";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var inboxMessages = await graphClient
.Users["tinywang#xx.onmicrosoft.com"]
.MailFolders["inbox"]
.Messages
.Request()
.Expand("attachments")
.Top(20)
.GetAsync();
Anyone, please help me to resolve this issue. Microsoft is going to disable Basic Authentication by end of this month, so I have to implement this before that.
Thanks in Advance.
I tried to reproduce the same in my environment and got below results:
I ran the same code as you and got same results without output or error like below:
using Azure.Identity;
using Microsoft.Graph;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "azure_ad_appid";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var inboxMessages = await graphClient
.Users["admin#xxxxxxxx.onmicrosoft.com"]
.MailFolders["inbox"]
.Messages
.Request()
.Expand("attachments")
.Top(20)
.GetAsync();
Response:
As I mentioned in the comments, you need to use interactive flow like authorization code for Delegated permissions.
I got the results successfully via Graph Explorer that use Delegated permissions like below:
GET https://graph.microsoft.com/v1.0/me/messages/<messageID>?$expand=attachments
Response:
You can get the sample C# snippet here:
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var message = await graphClient.Me.Messages["messageID"]
.Request()
.Expand("attachments")
.GetAsync();
Complete Sample Code:
using Azure.Identity;
using Microsoft.Graph;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "azure_ad_appid";
var clientSecret = "client_secret";
var authorizationCode = "code that you got in below request";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://learn.microsoft.com/dotnet/api/azure.identity.authorizationcodecredential
var authCodeCredential = new AuthorizationCodeCredential(
tenantId, clientId, clientSecret, authorizationCode, options);
var graphClient = new GraphServiceClient(authCodeCredential, scopes);
var message = await graphClient.Me.Messages["messageID"]
.Request()
.Expand("attachments")
.GetAsync();
To get the authorization code value, you can use below request:
https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/authorize
?client_id=<appID>
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=https://graph.microsoft.com/.default
&state=12345
When I ran the above request in browser. I got code along with redirect URI like below:

Microsoft Graph - Convert Read Emails

I was able to get all my emails using Microsoft Graph, but I am having to find a solution to get the information in a more visual way using a Console App. I cannot find a way to do that.
Code I currently have:
static async Task Main(string[] args)
{
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "";
var clientId = "";
var clientSecret = "";
var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
IUserMessagesCollectionPage msgs = await graphClient.Users["my email"].Messages.Request().GetAsync();
List<Message> messages = new List<Message>();
messages.AddRange(msgs.CurrentPage);
while (msgs.NextPageRequest != null)
{
msgs = await msgs.NextPageRequest.GetAsync();
messages.AddRange(msgs.CurrentPage);
}
Console.ReadLine();
}
I can list all my messages, but not actually convert it in a easy way to read.
this works for me:
GraphServiceClient graphClient = new(await GraphAuthAsync());
IUserMessagesCollectionPage graphRequest = await graphClient.Me.Messages
.Request()
.Filter("isRead eq false")
.Expand("attachments")
.Top(10)
.Select("id,from")
.GetAsync();
so, the property byte is missing.

Unable to send email via Microsoft Graph API (C# Console)

I followed these 2 links to create a console app for sending emails using Graph API:
https://learn.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=csharp
Microsoft Graph API unable to Send Email C# Console
I have added & granted the required permissions in Azure AD app:
I made sure to provide the client id, tenant id, client secret.
However, I see this error on running the console:
What am I missing?
Here is the code I tried from Microsoft Graph API unable to Send Email C# Console
static void Main(string[] args)
{
// Azure AD APP
string clientId = "<client Key Here>";
string tenantID = "<tenant key here>";
string clientSecret = "<client secret here>";
Task<GraphServiceClient> callTask = Task.Run(() => SendEmail(clientId, tenantID, clientSecret));
// Wait for it to finish
callTask.Wait();
// Get the result
var astr = callTask;
}
public static async Task<GraphServiceClient> SendEmail(string clientId, string tenantID, string clientSecret)
{
var confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantID)
.WithClientSecret(clientSecret)
.Build();
var authProvider = new ClientCredentialProvider(confidentialClientApplication);
var graphClient = new GraphServiceClient(authProvider);
var message = new Message
{
Subject = "Meet for lunch?",
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = "The new cafeteria is open."
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "myToEmail#gmail.com"
}
}
},
CcRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "myCCEmail#gmail.com"
}
}
}
};
var saveToSentItems = true;
await graphClient.Me
.SendMail(message, saveToSentItems)
.Request()
.PostAsync();
return graphClient;
}
Based on your code which generates the confidentialClientApplication, you are using Client credentials provider.
But the way you send the email is:
await graphClient.Me
.SendMail(message, saveToSentItems)
.Request()
.PostAsync()
It is calling https://graph.microsoft.com/v1.0/me/sendMail in fact.
But Client credentials flow doesn't support /me endpoint. You should call https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/sendMail endpoint in this case.
So the code should be:
await graphClient.Users["{id or userPrincipalName}"]
.SendMail(message, saveToSentItems)
.Request()
.PostAsync();
Or if you want to use /me/sendMail, choose Authorization code provider, where you should implement interactive login.
You can learn about the scenarios and differences between authorization code flow and client credentials flow.

Sending mail using a daemon application

I am having trouble sending an email from a daemon app. I can get the token with the Client Credential flow but I am unable to send an email with the Microsoft Graph API. I am getting the following error:
Code: BadRequest
Message: Found a function 'microsoft.graph.sendMail' on an open property. Functions on open properties are not supported.
Inner error:
AdditionalData:
request-id: e2e3bb60-2212-4c99-8858-d109aaf4f1cd
date: 2020-01-30T11:18:21
ClientRequestId: e2e3bb60-2212-4c99-8858-d109aaf4f1cd
}
Below is the coding for sending an email through Microsoft Graph.
private readonly IClientCredentialProvider _clientCredentialProvider;
public MailTransmitter()
{
AuthenticationConfig config = AuthenticationConfig.ReadFromJsonFile("appsettings.json"); // contains the tenantId, clientSecret and clientId
_clientCredentialProvider = new ClientCredentialProvider(config);
}
public async Task<bool> SendMail(List<UserEntitlement> sortedListByLastAccessDate)
{
//GraphServiceClient graphClient = new GraphServiceClient(_clientCredentialProvider.GetAuthorizationCodeProvider());
var result = await _clientCredentialProvider.GetClientToken(); // Get token using Client Credentials flow
var accessToken = result.AccessToken;
//should I pass the URL to the graphServiceClient like below? Is the URL right?
var graphServiceClient = new GraphServiceClient("https://graph.microsoft.com/v1.0/0a181b4b-a2fb-4e38-b23b-2c72adc882f2/users/c26d8491-82f8-4f08-990e-35a73ad61ede/memberOf", new DelegateAuthenticationProvider(async (requestMessage) => {
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
}));
var message = new Message
{
Subject = "Meet for lunch?",
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = "The new cafeteria is open."
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "Bla#hotmail.com"
}
}
},
From = new Recipient
{
EmailAddress = new EmailAddress {
Address = "bla.bla#test.nl"
}
}
};
var saveToSentItems = false;
//Error occurs here
await graphServiceClient.Users["c26d8491-82f8-4f08-990e-35a73ad61ede"]
.SendMail(message, saveToSentItems)
.Request()
.PostAsync();
return true;
}
In case you are wondering how I used the client credentials flow, take a look at: https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/tree/master/1-Call-MSGraph/daemon-console.
What is the problem exactly?
Thanks in advance!
The provided error occurs since invalid url is provided for GraphServiceClient, it expects the first argument to be service root url:
public GraphServiceClient(string baseUrl,IAuthenticationProvider authenticationProvider,IHttpProvider httpProvider = null)
in case of Microsoft Graph API, service root url consist of:
https://graph.microsoft.com is the Microsoft Graph API endpoint.
{version} is the target service version, for example, v1.0 or beta.
for instance, https://graph.microsoft.com/v1.0. Refer Calling the Microsoft Graph API for a details
Example
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
var scopes = new string[] {"https://graph.microsoft.com/.default"};
var result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();
var client = new GraphServiceClient(
"https://graph.microsoft.com/v1.0",
new DelegateAuthenticationProvider(async (requestMessage) =>
{
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", result.AccessToken);
}));
or via Client credentials provider for that matter:
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
var authProvider = new ClientCredentialProvider(app);
var client = new GraphServiceClient(authProvider);
Prerequisites: requires Microsoft.Graph.Auth package

Daemon using MSAL to MSGraph

I'm getting the error AADSTS70002: Error validating credentials. AADSTS50012: Client assertion audience claim does not match Realm issuer
when running this code.
string[] scopes = new string[]{"https://graph.microsoft.com/.default"};
var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
var cert = certStore.Certificates.Cast<X509Certificate2>().First(c => c.Thumbprint == "XXX-XXX etc");
var cas = new ClientAssertionCertificate(cert);
var cc = new Microsoft.Identity.Client.ClientCredential(cas);
var client = new Microsoft.Identity.Client.ConfidentialClientApplication("XX-XXX etc", "http://localhost", cc, new TokenCache(), new TokenCache() );
var authResult = await client.AcquireTokenForClientAsync(scopes);
var dap = new DelegateAuthenticationProvider(rm =>
{
rm.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", authResult.AccessToken);
return Task.FromResult(0);
});
var gClient = new GraphServiceClient(dap);
gClient.Me.Dump();
Error occurrs on the call to AcquireTokenForClientAsync() method.
I can not find any online documentation for MSAL and Daemon clients where no user authentication is possible.
Suggestions ?
Found the problem. I needed to use the second overload of the ConfidentialClientApplication constructor, and supply the authorisation like this.
string authorityFormat = "https://login.microsoftonline.com/{0}/v2.0";
string tennantId = "xxx-xx-xx";
then
var client = new Microsoft.Identity.Client.ConfidentialClientApplication("xxx-x-xx etc", string.Format(authorityFormat, tennantId), "http://localhost", cc, new TokenCache(), new TokenCache() );
The code Here pointed me in the right direction.

Categories