Microsoft-identity-web: [Question] How to get OBO token from an event handler

Created on 13 Aug 2020  路  13Comments  路  Source: AzureAD/microsoft-identity-web

How can I get an OBO access token in an event handler like:

[HttpPost]
public IActionResult ProcessData(string data)
{
    var processor = new Processor();

    processor.Finished += async (s, e) =>
    {
        var accessToken = await this
            ._tokenAcquisition
            .GetAccessTokenForUserAsync(new[] { "Files.ReadWrite" }, user: this.User);

        await WriteToOneDrive(accessToken, e.Data);
    };

    processor.processAsync(data); // Run async without awaiting

    return NoContent();
}

In this case the this.User is already disposed, and even without it, GetAccessTokenForUserAsync crashes with NullObjectException.

My process takes a very long time (hours).

How can I get the token inside a callback when I need it?

P2 needs documentation

Most helpful comment

I think that the problem is that the HttpContext is null, or HttpContext.Items is null:

https://github.com/AzureAD/microsoft-identity-web/blob/41195539af65836b464b063c186842896ab15e0e/src/Microsoft.Identity.Web/HttpContextExtensions.cs#L30

We should probably guard against these cases:

 return httpContext?.Items?[Constants.JwtSecurityTokenUsedToCallWebApi] as JwtSecurityToken;

as if the token is returned null, the AcquireTokenSilent will be tried, which should work for this scenario.

@jennyf19 @pmaytak @henrik-me I'm tempted to take this in 0.3.0-preview if you don't mind, as this would unblock our partner.

All 13 comments

@hraz-msft when your start your long running process, you should keep some claims about the user (at least the home tenant id and home object id), and then you can use ClaimsPrincipalFactory.FromTenantIdAndObjectId to get back a claims principal, and pass it instead of this.User.

https://github.com/AzureAD/microsoft-identity-web/blob/41195539af65836b464b063c186842896ab15e0e/src/Microsoft.Identity.Web/ClaimsPrincipalFactory.cs#L36

So I would try:

[HttpPost]
public IActionResult ProcessData(string data)
{
    var processor = new Processor();
    string oid = User.GetObjectId();
    string tid = User.GetTenantId();

    processor.Finished += async (s, e) =>
    {
        var accessToken = await this
            ._tokenAcquisition
            .GetAccessTokenForUserAsync(
              new[] { "Files.ReadWrite" }, 
              user: ClaimsPrincipalFactory.FromTenantIdAndObjectId(tid, oid));

        await WriteToOneDrive(accessToken, e.Data);
    };

    processor.processAsync(data); // Run async without awaiting

    return NoContent();
}

Hmm, it still crushing internally... The tid and oid are valid.

image

I think that the problem is that the HttpContext is null, or HttpContext.Items is null:

https://github.com/AzureAD/microsoft-identity-web/blob/41195539af65836b464b063c186842896ab15e0e/src/Microsoft.Identity.Web/HttpContextExtensions.cs#L30

We should probably guard against these cases:

 return httpContext?.Items?[Constants.JwtSecurityTokenUsedToCallWebApi] as JwtSecurityToken;

as if the token is returned null, the AcquireTokenSilent will be tried, which should work for this scenario.

@jennyf19 @pmaytak @henrik-me I'm tempted to take this in 0.3.0-preview if you don't mind, as this would unblock our partner.

@hraz-msft, which version of Microsoft Identity Web do you use?

As of 0.2.2-preview, we added a null-conditional operator, so GetTokenUsedToCallWebAPI is not called on a null HttpContext.
https://github.com/AzureAD/microsoft-identity-web/blob/fe145b3fbe75960faead1476176f7c63b8afd976/src/Microsoft.Identity.Web/TokenAcquisition.cs#L277

If you are using the latest version, then most likely the HttpContext.Items is null, in which case, Jean-Marc's code suggestion should help.

Hi @hraz-msft, is this still an issue for you?

Yes, it is still an issue that I don't know how to solve directly. I've found several workarounds like blocking the request until the operation done or sumbit a request to the sercer itself to simulate Webhook. But I don't have direct solution

Can you verify that the issue still exists in version 0.2.2-preview or later?

Yes, in 0.2.3-preview there is no null pointer exception, but there is another exception.

image

@hraz-msft there is a bug in this method. I'll get a fix out today, and it will be in our next release.

@hraz-msft do you want to try out the master branch and see if the initial issue is resolved?

Hi @jennyf19 I still can't get a token inside a callback with the latest master (error below).

I've open a repo with sample code with repro of the problem here

image

@hraz-msft does it still repro with Microsoft.Identity.Web 1.1.0 ?

Hi @jmprieur, Thank you! But I don't have the code and the app registration anymore. You can use my repro code to test it, it will be faster.
https://github.com/hraz-msft/ms-identity-javascript-react-spa-dotnetcore-webapi-obo/blob/master/ProfileAPI/Controllers/ProfileController.cs#L49

Was this page helpful?
0 / 5 - 0 ratings