2
votes

Trying to reverse engineer this sample app. Only i have not created my own service, just trying to get my profile information using the Microsoft Graph API. Getting the following error:

AdalSilentTokenAcquisitionException: Failed to acquire token silently as no token was found in the cache. Call method AcquireToken

I am pretty new to this but i have gone through all the stackoverflow issues related to that error and have not been able to figure it out.

I'm using Asp.net core latest version. I always fails with the above error on AcquireTokenSilentAsync. Any tips or ideas would be helpful.

Below is what i have so far.

Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseStaticFiles();

        app.UseSession();

        //app.UseCookieAuthentication();

        // Populate AzureAd Configuration Values
        Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"];
        ClientId = Configuration["Authentication:AzureAd:ClientId"];
        ClientSecret = Configuration["Authentication:AzureAd:ClientSecret"];
        GraphResourceId = Configuration["Authentication:AzureAd:GraphResourceId"];
        GraphEndpointId = Configuration["Authentication:AzureAd:GraphEndpointId"];

        // Configure the OWIN pipeline to use cookie auth.
        app.UseCookieAuthentication(new CookieAuthenticationOptions());

        app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
        {
            ClientId = ClientId,
            ClientSecret = ClientSecret,
            Authority = Authority,
            CallbackPath = Configuration["Authentication:AzureAd:CallbackPath"],
            ResponseType = OpenIdConnectResponseType.CodeIdToken,
            GetClaimsFromUserInfoEndpoint = false,

            Events = new OpenIdConnectEvents
            {
                OnRemoteFailure = OnAuthenticationFailed,
                OnAuthorizationCodeReceived = OnAuthorizationCodeReceived,
            }

        });

OnAuthorizationCodeReceived:

private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
    {
        // Acquire a Token for the Graph API and cache it using ADAL.  In the TodoListController, we'll use the cache to acquire a token to the Todo List API
        string userObjectId = (context.Ticket.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
        ClientCredential clientCred = new ClientCredential(ClientId, ClientSecret);
        AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectId, context.HttpContext.Session));
        AuthenticationResult authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
            context.ProtocolMessage.Code, new Uri(context.Properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey]), clientCred, GraphResourceId);

        // Notify the OIDC middleware that we already took care of code redemption.
        context.HandleCodeRedemption();



    }

MyProfileController:

public async Task<IActionResult> Index()
    {
        AuthenticationResult result = null;
        var user = new ADUser();

        try
        {
            string userObjectID = (User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
            AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID, HttpContext.Session));
            ClientCredential credential = new ClientCredential(Startup.ClientId, Startup.ClientSecret);
            var tc = authContext.TokenCache.ReadItems();
            result = await authContext.AcquireTokenSilentAsync(Startup.GraphResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.RequiredDisplayableId));

            HttpClient client = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
            HttpResponseMessage response = await client.SendAsync(request);

            if (response.IsSuccessStatusCode)
            {
                String responseString = await response.Content.ReadAsStringAsync();
                List<Dictionary<String, String>> responseElements = new List<Dictionary<String, String>>();
            }
        }
        catch (Exception)
        {

            throw;
        }
        return View();
    }
2

2 Answers

1
votes

I'd recommend using the UserIdentifierType.UniqueId as the sample does. Using the wrong identifier type can lead to cache misses. If the library can't find a token cache entry, it will fail with this error and you'll need to ask the user to sign-in again. Let me know if you already tried that and it didn't work.

0
votes

AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID));

Debug this line and check for authContext cache dictionary table for data. If records are 0 then ask/redirect user to login. Once user logs in cache table should be filled and toke should be available.

AuthenticationContext authContext = new AuthenticationContext(Startup.Authority,
                        new NaiveSessionCache(userObjectID));
                    if (authContext.TokenCache.Count == 0)
                    {
                        authContext.TokenCache.Clear();
                        CosmosInterface.Utils.AuthenticationHelper.token = null;
                        HttpContext.GetOwinContext().Authentication.SignOut(
                            OpenIdConnectAuthenticationDefaults.AuthenticationType,
                            CookieAuthenticationDefaults.AuthenticationType);
                    }