microsoftgraph / msgraph-sdk-dotnet-auth

Archived - use the TokenCredential classes provided by Azure.Identity. https://docs.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme
https://graph.microsoft.com
MIT License
78 stars 19 forks source link

Client credential provider fails #25

Closed tomatsue closed 5 years ago

tomatsue commented 5 years ago

When using ClientCredentialProvider, the following error occurs.

Unhandled Exception: System.AggregateException: One or more errors occurred. (Code: generalException
Message: An error occurred sending the request.
) ---> Microsoft.Graph.ServiceException: Code: generalException
Message: An error occurred sending the request.
 ---> Microsoft.Graph.Auth.AuthenticationException: Code: generalException
Message: Unexpected exception occured while authenticating the request.
 ---> System.UriFormatException: Invalid URI: The URI is empty.
   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
   at System.Uri..ctor(String uriString)
   at Microsoft.Identity.Client.ClientApplicationBase.CreateRequestParameters(Authority authority, IEnumerable`1 scopes, IAccount account, TokenCache cache) in C:\agent2\_work\69\s\src\Microsoft.Identity.Client\ClientApplicationBase.cs:line 384
   at Microsoft.Identity.Client.ConfidentialClientApplication.CreateRequestParameters(Authority authority, IEnumerable`1 scopes, IAccount user, TokenCache cache) in C:\agent2\_work\69\s\src\Microsoft.Identity.Client\Features\ConfidentialClient\ConfidentialClientApplication.cs:line 477
   at Microsoft.Identity.Client.ConfidentialClientApplication.AcquireTokenForClientCommonAsync(IEnumerable`1 scopes, Boolean forceRefresh, ApiIds apiId, Boolean sendCertificate) in C:\agent2\_work\69\s\src\Microsoft.Identity.Client\Features\ConfidentialClient\ConfidentialClientApplication.cs:line 434
   at Microsoft.Identity.Client.ConfidentialClientApplication.AcquireTokenForClientAsync(IEnumerable`1 scopes, Boolean forceRefresh) in C:\agent2\_work\69\s\src\Microsoft.Identity.Client\Features\ConfidentialClient\ConfidentialClientApplication.cs:line 280
   at Microsoft.Graph.Auth.ClientCredentialProvider.AuthenticateRequestAsync(HttpRequestMessage httpRequestMessage)

This might be because:

peombwa commented 5 years ago

@tomatsue Thanks for reporting this issue. You are correct in your finding and MSAL 2.7.1 doesn't appropriately handle empty strings as redirect urls for ConfidentialClient. We will handle this in our next preview release.

jodur commented 5 years ago

Any workarrounds for this issue at the moment?

peombwa commented 5 years ago

For now, you can new ConfidentialClientApplication and pass it to the ClientCredentialProvider constructor as such:

// Create a confidential client app
IConfidentialClientApplication confidentialApp = new ConfidentialClientApplication(clientId, "https://redirectUrl", clientCredential, null, tokenCache);

// Pass the confidential client app to client credential provider
IAuthenticationProvider clientCredentialProvider = new ClientCredentialProvider(confidentialApp);
jodur commented 5 years ago

Ok thnx, this worked for now!

Misiu commented 5 years ago

According to Readme:

Client credential provider Client credential provider is used by services and desktop applications to acquire Microsoft Graph access token without a user. The app should have previously registered a secret (app password or certificate) with Azure AD during the application registration. This provider leverages on MSALs Client Credential Flows to authenticate Microsoft Graph requests.

we should use this code:

IConfidentialClientApplication clientApplication = ClientCredentialProvider.CreateClientApplication(clientId, clientCredential);
ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(clientApplication);

unfortunally I get The URI is empty exception.

Fof a quick workaround I've used this:

IConfidentialClientApplication clientApplication = AuthorizationCodeProvider.CreateClientApplication(clientId, "https://daemon", clientCredential, null, tenant);
IAuthenticationProvider authenticationProvider = new ClientCredentialProvider(clientApplication);
IGraphServiceClient graphClient = new GraphServiceClient("https://graph.microsoft.com/v1.0", authenticationProvider);

but this requires to pass tenant and redirectUri and null as tokenStorageProvider. Please consider updating Readme or maybe fix this issue.

peombwa commented 5 years ago

This has been fixed as part of Microsoft.Graph.Auth 0.1.0-preview.2 release. Give it a try and let us know if addresses your scenario.

Misiu commented 5 years ago

This works great. The issue can be closed.

jodur commented 5 years ago

I now get a different error with te new©ode, while the suggested workarround worked for me:

MsalServiceException: AADSTS700016: Application with identifier 'a061d9f3-9ced-4149-b812-xxxx' was not found in the directory 'microsoft.com'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.

i use the following VB-code:

Dim clientApplication As ConfidentialClientApplication = ClientCredentialProvider.CreateClientApplication(clientId, Clientcredential)
        Dim authenticationProvider As ClientCredentialProvider = New ClientCredentialProvider(clientApplication)
        Dim graphServiceClient As GraphServiceClient = New GraphServiceClient(authenticationProvider)

        Dim Photo = Await graphServiceClient.Users(TxtEmail.Text).Photo.Content.Request().GetAsync()
Misiu commented 5 years ago

@jodur try using this:

IConfidentialClientApplication clientApplication = ClientCredentialProvider.CreateClientApplication(clientId, clientCredential, null, tenant);
IAuthenticationProvider authenticationProvider = new ClientCredentialProvider(clientApplication);
IGraphServiceClient graphClient = new GraphServiceClient(authenticationProvider);

You must pass tenant to CreateClientApplication, this solved the problem for me.

jodur commented 5 years ago

@Misiu , ok thnx this solved the issue!

sivabalaguru commented 5 years ago

I am trying to clear Identity Risk events using Post request as below ` IConfidentialClientApplication clientApplication = ConfidentialClientApplicationBuilder.Create("xxxx-xxxx-xxxx-xxxxx-xx").WithClientSecret("xxxxxxxxxxxxxxxxxxxxxxxxxxxx") .WithAuthority("https://login.microsoftonline.com/xxx.com/v2.0") .Build(); ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(clientApplication);

         IGraphServiceClient graphClient = new GraphServiceClient("https://graph.microsoft.com/beta",authenticationProvider,null);
         await graphClient.RiskyUsers.Dismiss(userIDs).Request().PostAsync();`

I never got succeded.

It encountered with error:

System.AggregateException: One or more errors occurred. ---> Microsoft.Graph.ServiceException: Code: generalException Message: An error occurred sending the request. ---> Microsoft.Graph.Auth.AuthenticationException: Code: generalException Message: Unexpected exception occured while authenticating the request. ---> System.NotImplementedException: See https://aka.ms/msal-net-3-breaking-changes at Microsoft.Identity.Client.ConfidentialClientApplication.AcquireTokenForClientAsync(IEnumerable`1 scopes, Boolean forceRefresh) at Microsoft.Graph.Auth.ClientCredentialProvider.d3.MoveNext() --- End of inner exception stack trace --- at Microsoft.Graph.Auth.ClientCredentialProvider.d3.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Graph.AuthenticationHandler.d__16.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

Should I pre-authenticate and get the token before making the actual graph api call?

If Yes, any pointers to the document?