question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How can I call ITokenAcquisition.GetAccessTokenForUserAsync from startup.cs

See original GitHub issue

Which version of Microsoft Identity Web are you using? Microsoft Identity Web 0.2.3-preview

Where is the issue?

  • Web app
    • Sign-in users
    • Sign-in users and call web APIs
  • Web API
    • Protected web APIs (validating tokens)
    • Protected web APIs (validating scopes)
    • Protected web APIs call downstream web APIs
  • Token cache serialization
    • In-memory caches
    • Session caches
    • Distributed caches
  • Other (please describe)

Is this a new or an existing app? a. The app is in production and I have upgraded to a new version of Microsoft Identity Web.

Repro

I’m trying to upgrade one of the projects I’m working on to use the Microsoft.Identity.Web nuget package. So far really working well but I’m having trouble figuring out how to add additional claims which I was previously doing by the following:

        services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
        {
            options.Events.OnAuthorizationCodeReceived = async ctx =>
            {
                var serviceProvider = services.BuildServiceProvider();
                var distributedCache = serviceProvider.GetRequiredService<IDistributedCache>();

                var identifier = ctx.Principal.FindFirst(ObjectIdentifierType)?.Value;

                var cca = ConfidentialClientApplicationBuilder.CreateWithApplicationOptions(new ConfidentialClientApplicationOptions()
                {
                    ClientId = "ClientId",
                    RedirectUri = "RedirectUri",
                    ClientSecret = "ClientSecret"
                })
                .WithAuthority(ctx.Options.Authority)
                .Build();

                var tokenCache = new SessionTokenCache(identifier, distributedCache);
                tokenCache.Initialize(cca.UserTokenCache);
                var token = await cca.AcquireTokenByAuthorizationCode(scopes, ctx.TokenEndpointRequest.Code).ExecuteAsync();

                ctx.HandleCodeRedemption(token.AccessToken, token.IdToken);

                // get the claims
                var claimService = serviceProvider.GetRequiredService<ClaimService>();
                var response = await apiClient.GetUserAdditionalClaimsAsync(token.AccessToken);
                
                // add the claims
            };

Now when I try to use the ITokenAcquisition.GetAccessTokenForUserAsync() method instead of using the ConfidentialClientApplicationBuilder

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftWebApp(options =>
    {
        Configuration.Bind("AzureAD", options);
        options.Events.OnAuthorizationCodeReceived = async ctx =>
        {
            var serviceProvider = services.BuildServiceProvider();
            var tokenAcquisition = serviceProvider.GetRequiredService<ITokenAcquisition>();

            var token = await tokenAcquisition.GetAccessTokenForUserAsync("scopes");

            // get the claims
            var claimService = serviceProvider.GetRequiredService<ClaimService>();
            var response = await apiClient.GetUserAdditionalClaimsAsync(token);

            // add the claims
        };
    })
    .AddMicrosoftWebAppCallsWebApi(Configuration, new[] { "scopes" })
    .AddDistributedTokenCaches();

I get the following error: enter image description here

Any help would be so much appreciated on how best to handle this. Thanks!

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:13 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
munkiicommented, Jan 18, 2021

We’d like to be able to centralise the configuration of our HttpClient in Startup.cs. So instead of

services.AddHttpClient<IMyService, MyService>();

We are moving to something like this,

services.AddHttpClient(nameof(MyService), (hc) =>
            {
                string apiBaseAddress = this.configuration["MyApi:BaseAddress"];
                hc.BaseAddress = new Uri(apiBaseAddress);
                hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            });

That works fine but if we wanted to move the following in there too

var accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(new[] { this.configuration["ClinicianApi:Scopes"] });
hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

We’d need access to ITokenAcquisition in Startup. There are a few references that suggest calling

var serviceProvider = services.BuildServiceProvider();
var tokenAcquisition = serviceProvider.GetRequiredService<ITokenAcquisition>()

However if you do that you get a warning when you build, “Avoid calls to BuildServiceProvider in ConfigureServices”

Therefore we would still like to know “How can I call ITokenAcquisition.GetAccessTokenForUserAsync from startup.cs”

1reaction
jmprieurcommented, Aug 18, 2020

@mia01

Would the following work for you?


       services.AddMicrosoftWebApp(Configuration)
                    .AddMicrosoftWebAppCallsWebApi(Configuration, new string[] { "scopes", "you", "need" ))
                    .AddMemoryTokenCaches();

        services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
        {
            var previousEventHandler = options.Events.OnAuthorizationCodeReceived;
            options.Events.OnAuthorizationCodeReceived = async ctx =>
            {
             // Ensure the Auth code is processed and the cache populated
             await previousEventHandler(ctx);

            // Get the token acquisition service here
           var tokenAcquistion = serviceProvider.GetRequiredService<ITokenAcquisition>();
           var token = await tokenAcquisition.GetAccessTokenForUserAsync("scopes");
         }
       }
Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - How can I call ITokenAcquisition. ...
Now when I try to use the ITokenAcquisition.GetAccessTokenForUserAsync() method instead of using the ConfidentialClientApplicationBuilder
Read more >
Related Posts - appsloveworld.com
Coding example for the question How can I call ITokenAcquisition.GetAccessTokenForUserAsync from startup.cs.
Read more >
ITokenAcquisition.GetAccessTokenForUserAsync Method
Typically used from an ASP.NET Core web app or web API controller. This method gets an access token for a downstream API on...
Read more >
Web API Authentication with Microsoft.Identity.Web
Microsoft.Identity.Web and Azure AD. The first thing I want to call out is in the Startup.cs file under ConfigureServices function.
Read more >
Microsoft.Identity.Web and Azure Functions - Honza's Blarg
The rest is just as easy as to call GetAccessTokenForUserAsync on ITokenAcquisition and if the scopes have been granted correctly, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found