Problem to send message to teams channel with Microsoft graph - c#

I'm working to send a message to Teams by using Graph API.
my application is a daemon application that sends a message automatically in the background.
I have written code like an official reference link below:
https://learn.microsoft.com/en-gb/graph/sdks/choose-authentication-providers?tabs=CS#client-credentials-provider
in my case, I use the client-credentials-provider but, I still can't send a message, and always get the below error message.
surely I have already registered my application in Azure and set for the grant of scope
How can I fix this?

Following this api document, you need to give Application api permission Teamwork.Migrate.All, and try this code below:
using Azure.Identity;
using Microsoft.Graph;
public void sendMesgAsync()
{
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 clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var chatMessage = new ChatMessage
{
Body = new ItemBody
{
Content = "Hello World"
}
};
await graphClient.Teams["{team-id}"].Channels["{channel-id}"].Messages
.Request()
.AddAsync(chatMessage);
}

Related

MS Graph SDK retrive mailboxSettings return invalid user error

I tried to use MS Graph API to implement a backend API to access other users email setting (for getting out-of-office message). As it is backend API, client credential flow is used. I already granted the permissions "MailboxSettings.Read" and "MailboxSettings.ReadWrite" with application type.
I used my free Azure account for testing. Assume my login account is test#hotmail.com, then my Azure domain is testhotmail.onmicrosoft.com.
I created one more user client#testhotmail.onmicrosoft.com
I can get the result using Graph Explorer as below
https://graph.microsoft.com/v1.0/users/test#hotmail.com
https://graph.microsoft.com/v1.0/users/test#hotmail.com/mailboxSettings
https://graph.microsoft.com/v1.0/users/client#testhotmail.onmicrosoft.com
But it return error for below using Graph Explorer
{
"error": {
"code": "ErrorInvalidUser",
"message": "The requested user 'client#testhotmail.onmicrosoft.com' is invalid."
} }
https://graph.microsoft.com/v1.0/users/client#testhotmail.onmicrosoft.com/mailboxSettings
3a. If call by MS Graph SDK to get the user info for client#testhotmail.onmicrosoft.com as below, it is success
var scopes = new[] { "https://graph.microsoft.com/.default" };
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var user = await graphClient.Users["client#testhotmail.onmicrosoft.com"].Request().GetAsync();
3b. If call by MS Graph SDK to get the user info for test#hotmail.com, it returns error
Microsoft.Graph.ServiceException: 'Code: Request_ResourceNotFound
Message: Resource 'test#hotmail.com' does not exist or one of its
queried reference-property objects are not present.
var user = await graphClient.Users["test#hotmail.com"].Request().GetAsync();
If call by MS Graph SDK to get the mailbox setting as below, it returned error
Microsoft.Graph.ServiceException: 'Code: ErrorInvalidUser Message: The
requested user 'test#hotmail.com' is invalid.
var scopes = new[] { "https://graph.microsoft.com/.default" };
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var mail = await graphClient.Users["test#hotmail.com"].Request().Select("MailboxSettings").GetAsync();
Or returned error for below
Microsoft.Graph.ServiceException: 'Code: ResourceNotFound Message:
Resource could not be discovered.
var mail = await graphClient.Users["client#testhotmail.onmicrosoft.com"].Request().Select("MailboxSettings").GetAsync();
using Microsoft.Graph;
using Azure.Identity;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "aad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var user = await graphClient.Users["xx#xx.onmicrosoft.com"]
.Request()
.Select("MailboxSettings")
.GetAsync();
var automaticRepliesSetting = user.MailboxSettings.AutomaticRepliesSetting;
Could you pls try this? By the way you may also try to add the 2 application permissions which mentioned in the document: MailboxSettings.Read, MailboxSettings.ReadWrite. And the most important is, your error message is invalid user, so I'm afraid you can use user_PrincipalName instead of myuser#hotmail.com. You can try to get the user_id in Azure AD potal or from the result for await graphClient.Users["myuser#hotmail.com"].Request().GetAsync();.
You are using hotmail.com , as per the doc you should also have either a personal Microsoft account with a mailbox on Outlook.com, or a Microsoft work or school account.
Hope this helps
Thanks

C# Graph API TranslateExchangeIds().PostAsync() HTTP Method not allowed

I am using the C# package to Microsoft Graph API. I can read messages from the Graph API. Now I'd like to translate the message IDs like shown here:
https://learn.microsoft.com/de-de/graph/api/user-translateexchangeids?view=graph-rest-1.0&tabs=csharp
var translatedIds = client.Users[firstMailboxElement.SourcePostbox]
.TranslateExchangeIds(toBeTranslated, ExchangeIdFormat.RestImmutableEntryId, ExchangeIdFormat.RestId)
.Request()
.PostAsync()
.Result;
When I do so I get the following Exception:
System.AggregateException
One or more errors occurred.
(Code: Request_BadRequest Message: Specified HTTP method is not allowed for the request target.
Inner error: AdditionalData: date: 2021-12-15T06:52:45 [...])
Which does not seem to make sense, since I cant change the HTTP Method.
Any ideas how to fix this?
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 inputIds = new List<String>()
{
"asdf"
};
var sourceIdType = ExchangeIdFormat.RestId;
var targetIdType = ExchangeIdFormat.RestImmutableEntryId;
var res = graphClient.Users["user_id"].TranslateExchangeIds(inputIds, targetIdType, sourceIdType).Request().PostAsync();
var a = res.Result;
I figured out, that the firstMailboxElement.SourcePostbox was null, when the exception occoured.
So the call went to client.Users[null], so the request URL was incomplete.

How do I use Service Principal authentication with an Azure Machine Learning Pipeline Endpoint in C#?

I'm trying to call an Azure Machine Learning Pipeline Endpoint I've set up using C# & the Machine Learning REST api.
I am certain that I have the Service Principal configured correctly, as I can successfully authenticate & hit the endpoint using the azureml-core python sdk:
sp = ServicePrincipalAuthentication(
tenant_id=tenant_id,
service_principal_id=service_principal_id,
service_principal_password=service_principal_password)
ws =Workspace.get(
name=workspace_name,
resource_group=resource_group,
subscription_id=subscription_id,
auth=sp)
endpoint = PipelineEndpoint.get(ws, name='MyEndpoint')
endpoint.submit('Test_Experiment')
I'm using the following example in C# to attempt to run my endpoint: https://learn.microsoft.com/en-us/azure/machine-learning/how-to-deploy-pipelines#run-a-published-pipeline-using-c
I'm attempting to fill auth_key with the following code:
var clientId = Environment.GetEnvironmentVariable("AZURE_CLIENT_ID");
var clientSecret = Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET");
var tenantId = Environment.GetEnvironmentVariable("AZURE_TENANT_ID");
var cred = new ClientSecretCredential(tenantId, clientId, clientSecret);
var auth_key = cred.GetToken(new Azure.Core.TokenRequestContext(new string[] {".default" }));
I receive a 401 (unauthorized).
What am I am doing wrong?
UPDATE *
I changed the 'scopes' param in the TokenRequestContext to look like:
var auth_key = cred.GetToken(new Azure.Core.TokenRequestContext(new string[] { "http://DataTriggerApp/.default" }));
http://DataTriggerApp is one of the servicePrincipalNames that shows up when i query my Service Principal from the azure CLI.
Now, when I attempt to use the returned token to call the Machine Learning Pipeline Endpoint, I receive a 403 instead of a 401. Maybe some progress?
Ok, through a lot of trial-and-error I was able to come up with two ways of acquiring a token that allows me to hit my Azure Machine Learning Pipeline Endpoint through the REST api. One uses Microsoft.Identity.Client & one uses Azure.Identity.
using Microsoft.Identity.Client;
...
public static async Task<string> GetAccessToken()
{
var clientId = Environment.GetEnvironmentVariable("AZURE_CLIENT_ID");
var clientSecret = Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET");
var tenantId = Environment.GetEnvironmentVariable("AZURE_TENANT_ID");
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
.Build();
var result = await app.AcquireTokenForClient(new string[] { "https://ml.azure.com/.default" }).ExecuteAsync();
return result.AccessToken;
}
Or:
using Azure.Identity;
...
public static async Task<string> GetAccessToken()
{
var clientId = Environment.GetEnvironmentVariable("AZURE_CLIENT_ID");
var clientSecret = Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET");
var tenantId = Environment.GetEnvironmentVariable("AZURE_TENANT_ID");
var cred = new ClientSecretCredential(tenantId, clientId, clientSecret);
var token = await cred.GetTokenAsync(new Azure.Core.TokenRequestContext(new string[] { "https://ml.azure.com/.default" }));
return token.Token;
}

Get members of a Security Group from Azure AD via Microsoft Graph

I have been trying to get the members of a specific securitygroup from Azure AD with the following code from Graph api
var members = await graphClient.Groups["{group-id}"].Members
.Request()
.GetAsync();
I followed the following link which says to give the following permission to the registered app link: https://learn.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0&tabs=csharp
and the permission for the application has been granted by the Admin;
But I keep getting the following error
ServiceException: Code: Authorization_RequestDenied Message: Insufficient privileges to complete the operation
I Using a client secret to create graphClient. And I grant permission like below, it works for me. You also can use other provider to do that.
My test code
public async Task<JsonResult> test()
{
// Values from app registration
var clientId = "fb2****-29ee-****-ab90-********0c7e1";
var clientSecret = "w7N*******........***yO8ig";
var scopes = new[] { "https://graph.microsoft.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "e4c9ab4e-****-40d5-****-230****57fb";
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
try
{
var members = await graphClient.Groups["13ad4665-****-43e9-9b0f-ca****eb"].Members.Request().GetAsync();
return Json(members);
}
catch (Exception e)
{
return Json("");
throw;
}
}
My test result
1st step : you will have to register an AD app and give permission on graph to read users and groups, please check this stackoverflow answer

404 error while creating Online Meeting using microsoft graph api c# without login into AzureActiveDirectory

I am trying to create Online Meeting using microsoft graph api without login into AzureActiveDirectory with asp.net web application.For this my app has below permissions which are required as per documentation https://learn.microsoft.com/en-us/graph/api/application-post-onlinemeetings?view=graph-rest-1.0&tabs=csharp with client credential auth flow https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow without immediate interaction with a user.I am able to retrive access token successfully as per client-creds-grant-flow.
I tried Micosoft.Graph and Micosoft.Graph.Beta still getting 404 error.
Create online meeting code
var graphClient = GetAuthenticatedClientCredential();
var onlineMeeting = new OnlineMeeting
{
StartDateTime = DateTimeOffset.Parse("2020-10-01T10:30:34.2444915+00:00"),
EndDateTime = DateTimeOffset.Parse("2020-10-01T11:00:34.2464912+00:00"),
Subject = "Create Online Meeting-Without user login to Office 365"
};
return await graphClient.Me.OnlineMeetings
.Request()
.AddAsync(onlineMeeting);
Access Token code
public static async Task<string> GetUserAccessTokenAsyncByCc()
{
IConfidentialClientApplication cca = ConfidentialClientApplicationBuilder.Create(appId)
.WithTenantId(appTenantId)
.WithClientSecret(appSecret)
.Build();
string[] scopes1 = new string[] { "https://graph.microsoft.com/.default" };
//string[] scopes1 = new string[] { "https://graph.microsoft.com/OnlineMeetings.ReadWrite.All" };
// string[] scopes1 = new string[] { "https://graph.microsoft.com/beta/OnlineMeetings.Read.All" };
//string[] scopes1 = new string[] { "https://graph.microsoft.com/beta/.default" };
var result = await cca.AcquireTokenForClient(scopes1).ExecuteAsync();
return result.AccessToken;
}
and Auth Provider code
public static GraphServiceClient GetAuthenticatedClientCredential()
{
DelegateAuthenticationProvider provider = new DelegateAuthenticationProvider(
async (requestMessage) =>
{
string accessToken = await GetUserAccessTokenAsyncByCc();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
});
GraphServiceClient graphClient = new GraphServiceClient(provider);
return graphClient;
}
app permission image
below are the necessary app permission
You can only use delegated permissions to create an onlineMeeting, so you must log in as a user, and you cannot use the client credential flow. You need to use the auth code flow to obtain the token.

Categories