ADAL authentication without prompting a dialog box

I have a console application registered in Azure AD that connects to CRM Online (using these steps ). It requests a web API.

The application should start without user interaction ... but, unfortunately, the AcquireTokenSilentAsync call always fails and only AcquireTokenAsync works. This will result in a user login dialog box that does not meet the user's requirements!

Is there a way to prevent this invitation , either by storing the login somewhere on the client machine (which has not worked yet), or perhaps by using a certificate (but how do you do this?) Or something else?

I am using the ADAL release for .NET v3.10.305110106. The following code is used for authentication:

 private static async Task PerformOnlineAuthentication() { _authInfo = new AuthInfo(); // This is just a simple class of parameters Console.Write("URL (include /api/data/v8.x): "); var url = Console.ReadLine(); BaseUri = new Uri(url); var absoluteUri = BaseUri.AbsoluteUri; _authInfo.Resource = absoluteUri; Console.Write("ClientId: "); var clientId = Console.ReadLine(); _authInfo.ClientId = clientId; Console.Write("RedirectUri: "); var redirectUri = Console.ReadLine(); _authInfo.RedirectUri = new Uri(redirectUri); var authResourceUrl = new Uri($"{_authInfo.Resource}/api/data/"); var authenticationParameters = await AuthenticationParameters.CreateFromResourceUrlAsync(authResourceUrl); _authInfo.AuthorityUrl = authenticationParameters.Authority; _authInfo.Resource = authenticationParameters.Resource; _authInfo.Context = new AuthenticationContext(_authInfo.AuthorityUrl, false); } private static async Task RefreshAccessToken() { if (!IsCrmOnline()) return; Console.WriteLine($"Acquiring token from: {_authInfo.Resource}"); AuthenticationResult authResult; try { authResult = await _authInfo.Context.AcquireTokenSilentAsync(_authInfo.Resource, _authInfo.ClientId); } catch (AdalSilentTokenAcquisitionException astae) { Console.WriteLine(astae.Message); authResult = await _authInfo.Context.AcquireTokenAsync(_authInfo.Resource, _authInfo.ClientId, _authInfo.RedirectUri, new PlatformParameters(PromptBehavior.RefreshSession)); } HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken); } 
+5
source share
2 answers

Thanks to @aravind , which pointed out the active-directory-dotnet-native-headless sample.

The example contains the FileCache class , which inherits from Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache . This class controls credential caching for an encrypted file on disk. This means that in the first run there is only one prompt, after which the credentials are saved locally.

The final pieces of the puzzle:

  • Calling another constructor signature to initialize the AuthenticationContext using FileCache:

     _authInfo.Context = new AuthenticationContext( _authInfo.AuthorityUrl, false, new FileCache()); 
  • Getting credentials from a user into a Microsoft.IdentityModel.Clients.ActiveDirectory.UserPasswordCredential object (see the TextualPrompt() method in the example )

  • Passing credentials to another method signature for AcquireTokenAsync() :

     authResult = await _authInfo.Context.AcquireTokenAsync( _authInfo.Resource, _authInfo.ClientId, userCredential); 
+5
source

If "the application should work without user interaction", use the ClientCredential stream, for example:

 public static string GetAccessTokenUsingClientCredentialFlow(Credential cred) { AuthenticationContext ac = new AuthenticationContext(cred.Authority); AuthenticationResult r = ac.AcquireTokenAsync(cred.ResourceId, new ClientCredential(cred.ClientId, cred.ClientSecret)).Result; return r.AccessToken; } 
0
source

All Articles