I'm getting the error
Unable to retrieve user's mysite URL
when I do any query to OneDrive. My complete code below and I'm just running it on Windows
using System;
using System.Collections.Generic;
using System.Net.Http.Headers;
using Microsoft.Graph;
using Microsoft.Identity.Client;
namespace MSGraphTests
{
class Program
{
static async System.Threading.Tasks.Task Main(string[] args)
{
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
IConfidentialClientApplication confidentialClient = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}/v2.0"))
.Build();
// Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
var authResult = await confidentialClient
.AcquireTokenForClient(scopes)
.ExecuteAsync();
var token = authResult.AccessToken;
Console.WriteLine(token);
// Build the Microsoft Graph client. As the authentication provider, set an async lambda
// which uses the MSAL client to obtain an app-only access token to Microsoft Graph,
// and inserts this access token in the Authorization header of each API request.
GraphServiceClient graphClient =
new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
{
// Add the access token in the Authorization header of the API request.
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token);
})
);
var children = await graphClient.Me.Drive.Root.Children
.Request()
.GetAsync();
}
}
}
Everything works fine in Graph Explorer and I have the Files.ReadWrite.All and User.Read.All permissions set both for Delegate and Application in Azure. I do get the token in the line Console.WriteLine(token).
I'm sure this is just an issue with my code and not permissions as I'm able to send queries using the O365 python library. How can I get this working?
Related
is it possible to retrieve token to azure aks server (same which is in .kube/config), using Azure Credentials, programatically c#/.net 6.
I know that in powershell to retrieve it i can run "az aks get-credentials" (yaml).
Yes, it is possible to retrieve a token from an Azure server using Azure credentials programmatically in C#.
Below is the code snippet, which I have followed and it worked for me.
IConfidentialClientApplication client = ConfidentialClientApplicationBuilder
.Create("<Client-Id>")
.WithClientSecret("<Client-Secret>")
.WithAuthority("https://login.microsoftonline.com/Tenant-ID")
.Build();
List<string> scopes = new List<string>
{
"https://graph.microsoft.com/.default"
};
AuthenticationResult result = await client
.AcquireTokenForClient(scopes)
.ExecuteAsync();
GraphServiceClient graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
requestMessage.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
}));
var res = await client.AcquireTokenForClient(scopes).ExecuteAsync();
string token = result.AccessToken;
Retrieving the token
I have a mobile app, which needs to call a REST API. Here is my code:
string url = $#"https://graph.microsoft.com/v1.0/solutions/bookingBusinesses/{adTenantId}/appointments";
string accessToken = new JwtSecurityTokenHandler().WriteToken(AuthService.JwtToken);
HttpClient client = new();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await client.GetAsync(url).ConfigureAwait(false);
This gives me error 401 (Unauthorized). I may be wrong, but it seems to me that it is because I use the access token based on the user's authentication. I probably need to call the API not as the user, but as my app. Buy I don't know how to get an access token for the app.
The app is registered with Azure AD and has necessary API permissions.
Assume you have set up the app for MS Graph API correctly, and you have the below configurations:
ClientId
ClientSecret
TenantId
Scopes
var app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithClientSecret(ClientSecret)
.WithAuthority(new Uri("https://login.microsoftonline.com/" + Tenant))
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
var accessToken = result.AccessToken;
Note that I use scope https://graph.microsoft.com/.default for all the permissions you have assigned to the application. You could use more specific scopes.
References.
I have created an ASP.NET Framework application using Microsoft Identify Platform from the standard template and used ConfidentialClient to acquire an access token. I now want to use this access token to call the Azure DevOps REST API.
My scenario is:
Open the application and immediately get asked to log in
Acquire an access token from ConfidentialClient
Execute an API call to Azure DevOps (e.g. GET https://dev.azure.com/{organization}/_apis/projects)
I believe I have completed steps 1 and 2 (code below), but when I execute the API is doesn't return the results, merely a HTML page asking me to login
The access token is recovered from the following code:
private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
{
var authCode = context.Code;
var tenantId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
var authority = aadInstance + tenantId;
//string[] scopes = new string[] { "https://graph.microsoft.com/User.Read" };
string[] scopes = new string[] { "https://app.vssps.visualstudio.com/user_impersonation" };
//string[] scopes = new string[] { "https://graph.microsoft.com/User.Read", "https://app.vssps.visualstudio.com/user_impersonation" };
// Get the access token from the ConfidentialClientApplication)
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithRedirectUri(redirectUri)
.WithClientSecret(clientSecret)
.WithAuthority(authority)
.Build();
var authResult = await app.AcquireTokenByAuthorizationCode(scopes, authCode).ExecuteAsync();
string accessToken = authResult.AccessToken;
Debug.WriteLine($"Access Token: {accessToken}");
//await GetProfileData(accessToken);
await GetProjectList(accessToken);
}
If I run this I get the access token but using this as the bearer token in my API call doesn't work. The method for calling the API is as follows:
private async Task GetProjectList(string accessToken)
{
// Get the Project List from the Azure DevOps API
var httpClient = new HttpClient();
var httpRequest = new HttpRequestMessage(HttpMethod.Get,
"https://dev.azure.com/gp-ementris/_apis/projects");
httpRequest.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(
"Bearer", accessToken);
var response = await httpClient.SendAsync(httpRequest);
if (response.IsSuccessStatusCode)
{
Debug.WriteLine(await response.Content.ReadAsStringAsync());
}
}
Can someone help explain how I can get the API to work with the token?
Thanks
This question already has answers here:
Microsoft Graph api code in C# displays only limited number of users
(2 answers)
Closed 3 years ago.
I am running below code :
using Microsoft.Graph;
using Microsoft.Identity.Client;
using System;
namespace MSGraphAPI
{
class Program
{
private static string clientId = "XXXXX";
private static string tenantID = "XXXX";
private static string objectId = "XXXX";
private static string clientSecret = "XXXX";
static async System.Threading.Tasks.Task Main(string[] args)
{
// IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
//.Create(clientId)
//.WithTenantId(tenantID)
//.WithClientSecret(clientSecret)
//.Build();
// ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);
// GraphServiceClient graphClient = new GraphServiceClient(authProvider);
// var users = await graphClient.Users
// .Request()
// .GetAsync();
var tenantId = "XXXX.onmicrosoft.com";
// The client ID of the app registered in Azure AD
var clientId = "XXXX";
// *Never* include client secrets in source code!
var clientSecret = "XXXX"; // Or some other secure place.
// The app registration should be configured to require access to permissions
// sufficient for the Microsoft Graph API calls the app will be making, and
// those permissions should be granted by a tenant administrator.
var scopes = new string[] { "https://graph.microsoft.com/.default" };
// Configure the MSAL client as a confidential client
var confidentialClient = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithAuthority($"https://login.microsoftonline.com/XXXXX.onmicrosoft.com/v2.0")
.WithClientSecret(clientSecret)
.Build();
// Build the Microsoft Graph client. As the authentication provider, set an async lambda
// which uses the MSAL client to obtain an app-only access token to Microsoft Graph,
// and inserts this access token in the Authorization header of each API request.
GraphServiceClient graphServiceClient =
new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) => {
// Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
var authResult = await confidentialClient
.AcquireTokenForClient(scopes)
.ExecuteAsync();
// Add the access token in the Authorization header of the API request.
requestMessage.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
})
);
// Make a Microsoft Graph API query
var users = await graphServiceClient.Users.Request().GetAsync();
Console.WriteLine(users.ToString());
IGraphServiceUsersCollectionPage userss = graphServiceClient.Users.Request().GetAsync().Result;
foreach (User user in userss)
{
Console.WriteLine("Found user: " + user.DisplayName);
}
}
}
}
I am getting only 100 users ( when i use debug and check the count and also put a watch on this variable) in the userss variable , but total number of users is around 1000 . I want to fetch all user details and also want to fetch users based on specific criteria using select or any other api in the same code.
Please help me.
Below code works to show all user details.
do
{
foreach (User user in users)
{
if (user.Mail != null)
{
if (user.Mail.Contains("Tom"))
{
Console.WriteLine("Hurray");
}
}
Console.WriteLine($"{user.Id}");
Flag++;
}
}
while (users.NextPageRequest != null && (users = await users.NextPageRequest.GetAsync()).Count > 0);
Can someone tell me if it will still be possible to use following authentication method with MS Graph after October 13, 2020?
public static async Task<string> GetUserAccessTokenAsync()
{
String APIToken = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX";
String LoginMail = "xxx#xxx.be";
String LoginWachtwoord = "xxxxxxxxxxx";
UserPasswordCredential userPasswordCredential = new UserPasswordCredential(LoginMail, LoginWachtwoord);
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/diekeure.be");
//Console App for Microsoft Graph
AuthenticationResult token = await authContext.AcquireTokenAsync("https://graph.microsoft.com/", APIToken, userPasswordCredential);
return token.AccessToken;
} /* GetUserAccessTokenAsync */
public static GraphServiceClient GetAuthenticatedClient()
{
GraphServiceClient graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) => {
string accessToken = await GetUserAccessTokenAsync();
// Append the access token to the request.
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
}));
return graphClient;
} /* GetAuthenticatedClient */
-> await graphClient....
Nuget package: Microsoft.IdentityModel.Clients.ActiveDirectory v3.19.8
I'm not really sure of this won't work either
Your sample isn't using Basic Authentication, it is using the OAuth Password grant. While not a very secure authentication mechanism (since you have to store a password), it is quite different than Basic Auth.
The email you referenced is also specific to legacy services like Exchange Web Services (EWS). Microsoft Graph is not a legacy API, it is the recommended/modern REST API for Microsoft services.