Skip to content

[Bug] Token Acquisition Fails Without HttpContext #273

Closed

Description

Which Version of Microsoft Identity Web are you using ?
0.1.5-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

[X] Other:

When token acquisition methods are invoked on the ITokenAcquisition supplied by DI outside of a valid HttpContext, these methods cause an exception. This is because the TokenAcquisition implementation makes reference to the properties of HttpContext without providing adequate null coalescence. While the package was likely designed to be used in the context of a valid HttpContext, there are scenarios in which the context will be null. The most notable example are Azure App Services WebJobs without Http Triggers. More specifically, consider a Web Job running on a Timer Trigger to perform an operation that requires AAD authentication, such as connecting to a Kusto cluster via AAD auth. In this context, when a method such as GetAccessTokenForAppAsync is invoked, it will trigger a NullReferenceException.

Is this a new or existing app?
This is a new app or experiment

Repro

  1. Create an Azure WebJob v3 C# .NET Core app with a TimerTrigger function.
  2. Add the appropriate AzureAd keys into the config, such as via appsettings.json.
  3. Create a standard ConfigureServices function with the following contents:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
     // MSAL based authentication initiation
    services.AddSignIn(Configuration);

    // Token acquisition service based on MSAL.NET
    services.AddWebAppCallsProtectedWebApi(Configuration, new string[] { "YOUR_SCOPE/.default" })
        .AddInMemoryTokenCaches();
    // ...
}
  1. Attempt to retrieve an access token for the application:
string token = tokenAcquisition.GetAccessTokenForAppAsync(new string[] { "YOUR_SCOPE/.default" }).Result;

Expected behavior
Retrieve an access token.

Actual behavior
Null Reference Exception

Possible Solution
Add null coalescence logic to src/Microsoft.Identity.Web/TokenAcquisition.cs:BuildConfidentialClientApplicationAsync. This could be accomplished by allowing a redirect uri to be passed into the function via any means other than extraction from HttpContext.

Additional context/ Logs / Screenshots
Temporary workaround is to manually construct an HttpContext before token acquisition:

if (httpContextAccessor.HttpContext is null)
{
    httpContextAccessor.HttpContext = new DefaultHttpContext();
    httpContextAccessor.HttpContext.Request.Scheme = "https";
    httpContextAccessor.HttpContext.Request.Host = new HostString("localhost");
}

string token = tokenAcquisition.GetAccessTokenForAppAsync(new string[] { "YOUR_SCOPE/.default" }).Result;

This temporary solution is a hack and should be avoided to prevent future breakage when package internals are updated.

Note: This is a first-party Microsoft issue. Please feel free to lookup my alias and ping me on teams for an internal example.

Activity

  1. jmprieur commented on Jun 30, 2020

    @jmprieur
    Collaborator

    Thanks for reporting Nicholas Boucher (@nickboucher)
    In your scenario, how would Microsoft.Identity.Web know the user if there is no HttpContext when it's called by a web hook?

  2. nickboucher commented on Jul 1, 2020

    @nickboucher
    Author

    Hi Jean-Marc Prieur (@jmprieur) -- thanks for the quick response. The app wouldn't know who the user is, but in this scenario there is no user. I'm specifically interested in the GetAccessTokenForAppAsync method, which acquires an access token on the behalf of the application (not a specific user).

  3. jmprieur commented on Jul 1, 2020

    @jmprieur
    Collaborator

    Oh, sorry, Nicholas Boucher (@nickboucher), I thought I had read GetAccessTokenForUser, yesterday.

  4. jennyf19 commented on Jul 13, 2020

    @jennyf19
    Collaborator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions