After installing the Microsoft Graph SDK and installing the NuGet package in my application when I add using Microsoft.Graph and trying to make a list of QueryOption, it doesn't even pick it up.
My QueryOption just stays red and there is nothing that it suggests me to add.
using Azure.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Graph.Core;
using Microsoft.Graph;
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
public GraphServiceClient showCalendar()
{
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "common";
var clientId = "xxx";
var clientSecret = "xxx";
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential,scopes);
return graphClient;
}
public void CalendarViews()
{
var graphClient = showCalendar();
var options = new List<QueryOption>()
{
new QueryOption("startDateTime", "2021-06-01T00:00:00.0000000"),
new QueryOption("endDateTime", "2021-06-30T23:59:59.9999999")
};
var events = graphClient.Me.CalendarView.Request(options).GetAsync().Result;
}
}
The parts where are QueryOption and Request are not getting picked put and I can't call them.
Related
[SOLVED, see the edits]
I am working in Linqpad 6, running a script that I made based on the following articles:
https://learn.microsoft.com/en-us/graph/api/user-post-users?view=graph-rest-1.0&tabs=csharp
https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS
Here is my script:
void Main()
{
Debug.WriteLine("yo");
UserCreator creator = new();
creator.CreateUser();
}
public class UserCreator
{
public async void CreateUser()
{
var scopes = new[] { "User.ReadWriteAll" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "<MY_TENANT_ID>";
// Value from app registration
var clientId = "<MY_APPLICATION_ID>";
var pca = PublicClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.Build();
// DelegateAuthenticationProvider is a simple auth provider implementation
// that allows you to define an async function to retrieve a token
// Alternatively, you can create a class that implements IAuthenticationProvider
// for more complex scenarios
var authProvider = new DelegateAuthenticationProvider(async (request) =>
{
// Use Microsoft.Identity.Client to retrieve token
var result = await pca.AcquireTokenByIntegratedWindowsAuth(scopes).ExecuteAsync();
request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
});
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var user = new User
{
AccountEnabled = true,
DisplayName = "John",
MailNickname = "John",
UserPrincipalName = "john#mail.com",
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "xWwvJ]6NMw+bWH-d"
}
};
await graphClient.Users
.Request()
.AddAsync(user);
}
}
I am trying to add a new user to an Azure AD B2C app, but the request is failing with an InnerException of:
"The system cannot contact a domain controller to service the authentication request."
I am suspecting I need more info for the script, such as the name of the registered App, but I cannot find anything about it in the documentation. I find it likely that the request is not returning the correct auth token.
Below is a screenshot of the error:
Updated code
This is my final, working result. Originally, I tried to create a user through my own account, but MFA got in the way. The actual way to do it, is through an app registration.
void Main()
{
UserCreator creator = new();
creator.CreateUser();
}
public class UserCreator
{
public async void CreateUser()
{
var clientId = "<CLIENT_ID>";
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "<TENANT_ID>";
var clientSecret = "<CLIENT_SECRET>";
// using Azure.Identity;
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);
var user = new{
Email = "test#mail.dk",
DisplayName = "TestUser",
Username = "Someusername",
};
var invitation = new Invitation
{
InvitedUserEmailAddress = user.Email,
InvitedUser = new User
{
AccountEnabled = true,
DisplayName = "TestUser",
CreationType = "LocalAccount",
PasswordPolicies = "DisableStrongPassword",
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "Test123456",
}
},
InvitedUserType = "member",
SendInvitationMessage = true,
InviteRedirectUrl = "someurl.com"
};
await graphClient.Invitations
.Request()
.AddAsync(invitation);
Console.Write("completed");
}
}
Try to set Azure AD authority by .WithAuthority instead of WithTenantId.
There is a typo in your scopes. Required permission is User.ReadWrite.All not User.ReadWriteAll.
var scopes = new[] { "User.ReadWrite.All" };
...
var pca = PublicClientApplicationBuilder
.Create(clientId)
.WithAuthority($"https://login.microsoftonline.com/{tenantId}")
.WithDefaultRedirectUri()
.Build();
I have create a c# custom application to create chat using one-on-one chat using user principal name. I want to show the response header into the Textbox when the user click the create button. I have follow the article below Get Response Header data from Post Call to get the response but currently I'm having some errors.
Coding part of Create Chat
private async void button2_Click(object sender, EventArgs e)
{
var scopes = new[] { "Directory.Read.All", "Directory.ReadWrite.All", "User.Read", "User.Read.All", "User.ReadBasic.All", "User.ReadWrite" };
{
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "5exxxx3-376a-43b1-9xxx0c-ef3xxxf8bx0";
// Value from app registration
var clientId = "35xxx-5c92-4xxx9-8500-635xxxe8af";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var userName = "ng.xxxxxi.com";
var password = "Aaxxxxxx";
// https://learn.microsoft.com/dotnet/api/azure.identity.usernamepasswordcredential
var userNamePasswordCredential = new UsernamePasswordCredential(
userName, password, tenantId, clientId, options);
GraphServiceClient graphClient = new GraphServiceClient(userNamePasswordCredential, scopes);
var chat = new Chat
{
ChatType = ChatType.OneOnOne,
Members = new ChatMembersCollectionPage()
{
new AadUserConversationMember
{
Roles = new List<String>()
{
"owner"
},
AdditionalData = new Dictionary<string, object>()
{
{"user#odata.bind", "https://graph.microsoft.com/v1.0/users[comboBox2.Text]"}
}
},
new AadUserConversationMember
{
Roles = new List<String>()
{
"owner"
},
AdditionalData = new Dictionary<string, object>()
{
{"user#odata.bind", "https://graph.microsoft.com/v1.0/users/[comboBox3.Text]"}
}
}
}
};
var requestUrl = graphClient.Chats.Request().RequestUrl;
var content = "json_content";
var hrm = new HttpRequestMessage(HttpMethod.Post, requestUrl);
hrm.Content = new StringContent(content, System.Text.Encoding.UTF8, "aplication/json");
// Authenticate (add access token)
await graphClient.AuthenticationProvider.AuthenticateRequestAsync(hrm);
// Send the request and get the response.
var response = await graphClient.HttpProvider.SendAsync(hrm);
if (!response.IsSuccessStatusCode)
{
throw new ServiceException(
new Error
{
Code = response.StatusCode.ToString(),
Message = await response.Content.ReadAsStringAsync()
});
}
else
{
// read header values
var headerValues = response.Headers.GetValues(textBox2.Text);
}
await graphClient.Chats
.Request()
.AddAsync(chat);
}
}
I created a C# console application to send email using Microsoft Graph API. On adding Mail.Send Delegated Permission to my application, I see the following exception:
I have enabled 'Allow public client flows':
The application has Mail.Send permission:
Here is my code:
public async Task SendMail(string subject, string content, string recipientAddress)
{
var publicClientApplication = PublicClientApplicationBuilder
.Create("<client id>")
.WithTenantId("<tenant id>")
.Build();
string[] scopes = new string[] { "mail.send" };
UsernamePasswordProvider authProvider = new UsernamePasswordProvider(publicClientApplication, scopes);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var message = new Message
{
Subject = subject,
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = content
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress { Address = recipientAddress }
}
}
};
var securePassword = new SecureString();
foreach (char c in _senderPassword)
securePassword.AppendChar(c);
var saveToSentItems = true;
await graphClient.Me
.SendMail(message, saveToSentItems)
.Request().WithUsernamePassword(_senderAddress, securePassword)
.PostAsync();
}
What am I missing?
You need to meet the following points:
You must have Mail.Send delegation permissions, you can use jwt.ms to parse your access token to view scp claims:
2.Ensure that your account has an Exchange online license under O365 subscription. See: assign licenses to one user.
My code for your reference:
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Identity.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace devicecode
{
class Program
{
static async Task Main(string[] args)
{
string graphScope = "User.Read User.ReadBasic.All Mail.Send Mail.Send.Shared";
var graphScopes = graphScope.Split(' ').ToArray();
// Build a client application.
IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
.Create("My clienid")
.Build();
DeviceCodeProvider authProvider = new DeviceCodeProvider(publicClientApplication, graphScopes);
// Create an authentication provider by passing in a client application and graph scopes.
// Create a new instance of GraphServiceClient with the authentication provider.
GraphServiceClient 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 = "mytestaccount"
}
}
}
};
var saveToSentItems = false;
await graphClient.Me
.SendMail(message, saveToSentItems)
.Request()
.PostAsync();
}
}
}
print:
I have created a small Console App to send email using Microsoft Graph API.
Tutorial Used
https://learn.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=csharp
Error
ServiceException: Code: NoPermissionsInAccessToken Message: The token
contains no permissions, or permissions can not be understood.
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Graph.Extensions;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
namespace GraphAPI
{
class Program
{
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)
{
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantID)
.WithClientSecret(clientSecret)
.Build();
ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient 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;
}
}
}
Here is the Screenshot of permissions I gave to the AD APP
So, Can anybody guide me where I am going wrong
Based on your screenshot, you haven't grant admin consent to Mail.Send application permission.
Click the grant admin consent button under api permissions.
Update:
Interactive provider:
string[] scopes = { "Mail.Send" };
string clientId = "";
IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
.Create(clientId)
.WithRedirectUri("https://localhost")
.Build();
InteractiveAuthenticationProvider authProvider = new InteractiveAuthenticationProvider(publicClientApplication, scopes);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
I get a 403 Forbidden response from Azure AD when trying to create an application using the Graph API:
private static void CreateApplicationViaPost(string tenantId, string clientId, string clientSecret)
{
var authContext = new AuthenticationContext(
string.Format("https://login.windows.net/{0}",
tenantId));
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
AuthenticationResult result = authContext.AcquireToken(
"https://graph.windows.net",
clientCred);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
const string json = #"{ displayName: ""My test app"", logoutUrl: ""http://logout.net"", identifierUris: [ ""http://identifier1.com"" ], replyUrls: [ ""http://replyUrl.net"" ] }";
HttpResponseMessage response = client.PostAsync(
string.Format("https://graph.windows.net/{0}/applications?api-version=1.6", tenantId),
new StringContent(json, Encoding.UTF8, "application/json")).Result;
Console.WriteLine(response.ToString());
}
The client registered in Azure AD has all the permissions:
What am I missing?
EDIT:
I registered a native client in Azure AD and gave it permissions to write to Windows Azure Active Directory. This code create an application in Azure AD:
private static void CreateApplicationViaPost(string tenantId, string clientId, string redirectUri)
{
var authContext = new AuthenticationContext(
string.Format("https://login.windows.net/{0}",
tenantId));
AuthenticationResult result = authContext.AcquireToken("https://graph.windows.net", clientId, new Uri(redirectUri), PromptBehavior.Auto);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
const string json = #"{ displayName: ""My test app1"", homepage: ""http://homepage.com"", logoutUrl: ""http://logout1.net"", identifierUris: [ ""http://identifier11.com"" ], replyUrls: [ ""http://replyUrl1.net"" ] }";
HttpResponseMessage response = client.PostAsync(
string.Format("https://graph.windows.net/{0}/applications?api-version=1.6", tenantId),
new StringContent(json, Encoding.UTF8, "application/json")).Result;
Console.WriteLine(response.ToString());
}
Modifying the directory requires consent from an admin user. So you'll need to acquire an access token from an user, e.g. through OAuth, instead of a token for the client.
There are quite a few of samples at GitHub that show the authorisation flow, e.g. https://github.com/AzureADSamples/WebApp-GraphAPI-DotNet.
Adding to #MrBrink's answer - you need to make sure the person adding the permissions in the Azure Active Directory UI is actually an administrator. If you have access to Azure Active Directory and are not an administrator it WILL still let you assign permissions - however they will only apply at a user scope.
An alternative would be to use the ActiveDirectoryClient from the Microsoft.Azure.ActiveDirectory.GraphClient NuGet package.
private static async Task CreateApplication(string tenantId, string clientId,
string redirectUri)
{
var graphUri = new Uri("https://graph.windows.net");
var serviceRoot = new Uri(graphUri, tenantId);
var activeDirectoryClient = new ActiveDirectoryClient(serviceRoot,
async () => AcquireTokenAsyncForUser("https://login.microsoftonline.com/" + tenantId,
clientId, redirectUri));
var app = new Application
{
Homepage = "https://localhost",
DisplayName = "My Application",
LogoutUrl = "https://localhost",
IdentifierUris = new List<string> { "https://tenant.onmicrosoft.com/MyApp" },
ReplyUrls = new List<string> { "https://localhost" }
};
await activeDirectoryClient.Applications.AddApplicationAsync(app);
Console.WriteLine(app.ObjectId);
}
private static string AcquireTokenAsyncForUser(string authority, string clientId,
string redirectUri)
{
var authContext = new AuthenticationContext(authority, false);
var result = authContext.AcquireToken("https://graph.windows.net",
clientId, new Uri(redirectUri), PromptBehavior.Auto);
return result.AccessToken;
}