microsoftgraph/msgraph-sdk-dotnet-auth

Client credential provider fails

Closed this issue · 11 comments

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:

@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

Any workarrounds for this issue at the moment?

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

Ok thnx, this worked for now!

Misiu commented

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.

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

This works great. The issue can be closed.

jodur commented

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

@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

@Misiu , ok thnx this solved the issue!

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.d__3.MoveNext()
--- End of inner exception stack trace ---
at Microsoft.Graph.Auth.ClientCredentialProvider.d__3.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?