AcquireTokenSilent is Failing to acquire token silently?

10,892

AcquireTokenSilentAsync will try all ways it can to get you a valid token without prompting for an interactive auth request. If it cannot (through the cache or refresh token), then it will generate an exception.

You can catch this exception and decide to prompt for an interactive auth or silently fail and ask your end users to sign in later depending on your app logic. Here is the reference docs for this interactive call.

            AuthenticationResult result;
            try
            {
                 result = await authContext.AcquireTokenSilentAsync(resourceId, clientId);
            }
            catch (AdalException ex)
            {
                if (ex.ErrorCode == "failed_to_acquire_token_silently")
                {
                    // There are no tokens in the cache. 
                    result = await authContext.AcquireTokenAsync(resourceId, clientId, redirectUri, new PlatformParameters(PromptBehavior.Always));

                }
                else
                {
                    // An unexpected error occurred.
                    string message = ex.Message;
                    if (ex.InnerException != null)
                    {
                        message += "Inner Exception : " + ex.InnerException.Message;
                    }
                    MessageBox.Show(message);
                }

Here is a great code sample .NET MVC app that shows you how to use ADAL.

Share:
10,892
Ray
Author by

Ray

Updated on June 04, 2022

Comments

  • Ray
    Ray almost 2 years

    I have a hosted application on Azure. In the SiteMaster page (master page), I am trying to get all the user's AD groups because my application is a role-based application where each user belongs to an Azure group and each group can perform certain functionalities.

    My code in the page load event is like the following:

    private static string clientId = ConfigurationManager.AppSettings["ida:ClientID"];
    private static string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
    private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
    private static string graphResourceId = "https://graph.windows.net";
    
    protected void Page_Load(object sender, EventArgs e)
    {
          if (Request.IsAuthenticated)
          {
              IList<string> groups = GetUserData();
          }
    }
    

    Notice that I am calling the function 'GetUserData()' that actually brings all the groups that a user belongs to. The code of this function is like the following:

            public IList<string> GetUserData()
            {
                string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
                string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
    
                Uri servicePointUri = new Uri(graphResourceId);
                Uri serviceRoot = new Uri(servicePointUri, tenantID);
                ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot,
                        async () => await GetTokenForApplication());
    
                IList<string> groupMembership = new List<string>();
                // use the token for querying the graph to get the user details
                IUser user = activeDirectoryClient.Users
                    .Where(u => u.ObjectId.Equals(userObjectID))
                    .ExecuteAsync().Result.CurrentPage.ToList().First();
                var userFetcher = (IUserFetcher)user;
                requestor = user.DisplayName;
                IPagedCollection<IDirectoryObject> pagedCollection = userFetcher.MemberOf.ExecuteAsync().Result;
                do
                {
                    List<IDirectoryObject> directoryObjects = pagedCollection.CurrentPage.ToList();
                    foreach (IDirectoryObject directoryObject in directoryObjects)
                    {
                        if (directoryObject is Group)
                        {
                            var group = directoryObject as Group;
                            groupMembership.Add(group.DisplayName);
                        }
                    }
                    pagedCollection = pagedCollection.GetNextPageAsync().Result;
                } while (pagedCollection != null);
    
                return groupMembership;
            }
    

    The 'GetUserData()' function is calling another function called 'GetTokenForApplication()' which is responsible of getting a token form Azure. The source code of the previous function is like the following:

      protected async Task<string> GetTokenForApplication()
        {
            string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
            string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
            string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
    
            // get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
            ClientCredential clientcred = new ClientCredential(clientId, appKey);
            // initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
            AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID));
            AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenSilentAsync(graphResourceId, clientcred, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
            return authenticationResult.AccessToken;
    
    
        } 
    

    My problem is sometimes when a user tries to login to my application s/he gets the error Failed to acquire token silently. Call method AcquireToken

    This error happens in certain cases that I don't know and when it happens, it doesn't affect all the users. Some users are still able to get in and not get this error. Any suggestion or idea of why is this happening and how to solve an error like that?

    Here is my Stack Trace:

    [AdalSilentTokenAcquisitionException: Failed to acquire token silently. Call method AcquireToken]
       Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenSilentHandler.SendTokenRequestAsync() +98
       Microsoft.IdentityModel.Clients.ActiveDirectory.<RunAsync>d__0.MoveNext() +1807
       System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13891908
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
       Microsoft.IdentityModel.Clients.ActiveDirectory.<AcquireTokenSilentCommonAsync>d__10.MoveNext() +317
       System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13891908
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
       Microsoft.IdentityModel.Clients.ActiveDirectory.<AcquireTokenSilentAsync>d__5c.MoveNext() +268
       System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13891908
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
       MRTWebApplication.<GetTokenForApplication>d__6.MoveNext() +539
       System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13891908
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
       MRTWebApplication.<<GetUserData>b__5_0>d.MoveNext() +194
       System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13891908
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
       Microsoft.Azure.ActiveDirectory.GraphClient.Extensions.<SetToken>d__1.MoveNext() +207
       System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13891908
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
       Microsoft.Azure.ActiveDirectory.GraphClient.Extensions.<ExecuteAsync>d__4d`2.MoveNext() +986
       System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13891908
       System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
       Microsoft.Azure.ActiveDirectory.GraphClient.Extensions.<<ExecuteAsync>b__0>d__2.MoveNext() +263
    
    [AggregateException: One or more errors occurred.]
       System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) +4465776
       MRTWebApplication._Default.GetUserData() +778
       MRTWebApplication._Default.Page_Load(Object sender, EventArgs e) +43
       System.Web.UI.Control.OnLoad(EventArgs e) +109
       System.Web.UI.Control.LoadRecursive() +68
       System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4498
    

    Thanks!

  • Ray
    Ray about 7 years
    Thank you @DanielDobalian for your answer. I thought about the same thing. How can I let the application to force the user to re-sign in if there was no token?
  • Daniel Dobalian
    Daniel Dobalian about 7 years
    Checkout the line result = await authContext.AcquireTokenAsync(resourceId, clientId, redirectUri, new PlatformParameters(PromptBehavior.Always));. This will force an interaction auth request.
  • Wolfzoon
    Wolfzoon over 6 years
    Code sample seems outdated, it's all about Owin and not a single reference to AcquireToken.
  • Daniel Dobalian
    Daniel Dobalian over 6 years
    @Wolfzoon good point, that sample is all OWIN OIDC, Here's a code sample that shows the behavior of OWIN + ADAL.
  • aj go
    aj go about 3 years
    Is there something like instead of informing the user to reauth, it should generate new token using the available parameters?
  • Nan Yu
    Nan Yu about 3 years
    reauth need the username/password right ? browser also can't help you click the login button even remember the username and password , that is for security consideration
  • aj go
    aj go almost 3 years
    I tried this approach and open in incognito but its not working for me