aspnetcore: Error retrieving the current token in a Blazor application after successful authentication in Azure B2C with Msal

This issue has been moved from a ticket on Developer Community.


I have created a Blazor application and I use Msal to do authentication following the examples from Azure B2C. With my B2C configuration in the server, I can successfully login, I get the User, the claims and I can call the api. I would need to have access to the token during development to be able to use that token to call my api services directly using swagger. So during Debugging I wanted to print the token on screen to copy and paste.

However, when I try to get the token in the Client after successful login, I get an Exception: An exception occurred executing JS interop: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires

This is a very confusing exception and doesn’t seem to explain the type of error that is occurring. It seems that is not doing any validation during the parsing or pre-parsing. So not sure why this is happening.

More details:

I initialise with this:

builder. Services.AddMsalAuthentication(options =>
            {
                builder. Configuration.Bind("AzureAdB2C", options. ProviderOptions.Authentication);

//options. ProviderOptions.DefaultAccessTokenScopes.Add("02200220-20202-2020-2020-202020200202002"); // I tried to put the application Id a per documentation and it doesn't work

options. ProviderOptions.DefaultAccessTokenScopes.Add("openid");
                options. ProviderOptions.DefaultAccessTokenScopes.Add("offline_access");

// request scope to access the API
                options. ProviderOptions.AdditionalScopesToConsent.Add("https://myb2c.onmicrosoft.com/whateverApp/MyAPI");

options. ProviderOptions.LoginMode = "redirect";
            });

I also use a custom AuthorizationMessageHandler to be able to call the api, which works well.

However, when in my code I call the code to retrieve the Token, I get the exception + one unhandled exception:

[Inject]
public IAccessTokenProvider TokenProvider { get; set; }
...
var accessTokenResult = await TokenProvider.RequestAccessToken(); // <-- This throws exception

And additionally there is an unhandled exception:

Unhandled Exception:
System.Text.Json.JsonException: Invalid JSON
   at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.EndInvokeJS(JSRuntime jsRuntime, String arguments)
   at Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime.<>c.<EndInvokeJS> b__7_0(String argsJson)
   at Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyCallQueue.Schedule[String](String state, Action`1 callback)
   at Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime.EndInvokeJS(String argsJson)
Uncaught Error: System.Text.Json.JsonException: Invalid JSONThe thread 0x1b444 has exited with code 0 (0x0).

I have tried in B2C to set the configuration, and I’m able to run the SignIn flow redirecting to jwt.ms passing the token and decoding it.

image.png

And I get the token decoded when redirecting directly to jwt.ms:

image.png


Original Comments

Feedback Bot on 11/12/2021, 00:15 AM:

We have directed your feedback to the appropriate engineering team for further evaluation. The team will review the feedback and notify you about the next steps.


Original Solutions

(no solutions)

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 2
  • Comments: 58 (18 by maintainers)

Most upvoted comments

Hi @mkArtakMSFT @TanayParikh ,

I saw that nothing changed here (and I forget to push the sample repository).

This is available herehttps://github.com/kbeaugrand/SampleOpenIDConnect

I’m using Okta identity provider, the settings are present at Program.cs#L16-21

Do we have any known workaround to handle this issue till it is officially fixed?

@kbeaugrand here is a sample that shows how you can customize the JS we provide. It uses MSAL, but the steps are equivalent for OpenID Connect.

https://github.com/javiercn/BlazorWasmMsalSample

@SariDev unfortunately I didn’t understand correctly what is expected to be the correct solution. The suggested workaround doesn’t seem clear for me. Furthermore, I cannot understand why this issue is taking so much time since it’s a blocking point for integrating Blazor WebAssembly with OpenID Connect…

So, using new Blazor project with default B2C configuration is still erroring on the profile page. So lets wait as the other guys on this 😡 image image

@Spaceman1861

Can you print in the discussion, the tokens you have in the session storage (not the values, just the keys) ? Maybe I miss understand the OAuth 2.0 (and OpenId protocol), but with the AspNetCore Assembly, I can only work with the id_token. To my standing point, my WebAssembly App should be considered as a client app, and should act to my API on behalf of the user. So my API refuse the id_token as the Bearer token because it has been issued for identification, not for authorization…

image Source: https://auth0.com/blog/id-token-access-token-what-is-the-difference/.

@javiercn, I cannot understand the decision to move the fix to this issue to .NET 7. What is the solution to use WebAssembly Authenticated (even in MSAL or OpenIdConnect) and provide the access token to the API part properly ?

I have two issues :

  • When requesting only the id_token from the authorization endpoint, the process works, but while requesting the access_token, the application fails with the $.token.expires issue
  • When requesting both id_token and token, the authentication fails, the browser tries 2 times to authenticate and redirects me to an error page (however the Identity provider sends correctly the id_token and access_token to the app). image

These two issues makes the Blazor WebAssembly not usable with an authenticated resource !

@kbeaugrand same for me.

Maybe someone can clarify how those workarounds should be implemented with more details.

Furthermore, I cannot understand why this issue is taking so much time since it’s a blocking point for integrating Blazor WebAssembly with OpenID Connect…

I’m also suprises by this. One would expect that this is a heavily requested Feature and that it should work without issues

@kbeaugrand we are looking into it, but it seems the issue happens when the app is not requesting an access token.

Using 6.0.4 and I’m affected by this issue too. Any timeline on a fix?

From the Blazor WASM when calling var tokenRequest = await TokenProvider.RequestAccessToken(); i get the following error:

 blazor.webassembly.js:1 
        
       crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: An exception occurred executing JS interop: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 73.. See InnerException for more details.
Microsoft.JSInterop.JSException: An exception occurred executing JS interop: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 73.. See InnerException for more details.
 ---> System.Text.Json.JsonException: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 73.
 ---> System.InvalidOperationException: Cannot get the value of a token type 'Null' as a string.
   at System.Text.Json.Utf8JsonReader.TryGetDateTimeOffset(DateTimeOffset& value)
   at System.Text.Json.Utf8JsonReader.GetDateTimeOffset()
   at System.Text.Json.Serialization.Converters.DateTimeOffsetConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1[[System.DateTimeOffset, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.AccessToken, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, AccessToken& value)
   at System.Text.Json.Serialization.JsonConverter`1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.AccessToken, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, AccessToken& value)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.AccessToken, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.InternalAccessTokenResult, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, InternalAccessTokenResult& value)
   at System.Text.Json.Serialization.JsonConverter`1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.InternalAccessTokenResult, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, InternalAccessTokenResult& value)
   at System.Text.Json.Serialization.JsonConverter`1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.InternalAccessTokenResult, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   --- End of inner exception stack trace ---
   at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
   at System.Text.Json.Serialization.JsonConverter`1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.InternalAccessTokenResult, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.Serialization.JsonConverter`1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.InternalAccessTokenResult, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].ReadCoreAsObject(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadCore[Object](JsonConverter jsonConverter, Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.Read[Object](Utf8JsonReader& reader, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize(Utf8JsonReader& reader, Type returnType, JsonSerializerOptions options)
   at Microsoft.JSInterop.JSRuntime.EndInvokeJS(Int64 taskId, Boolean succeeded, Utf8JsonReader& jsonReader)
   --- End of inner exception stack trace ---
   at Microsoft.JSInterop.JSRuntime.<InvokeAsync>d__16`1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.InternalAccessTokenResult, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext()
   at Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteAuthenticationService`3.<RequestAccessToken>d__22[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteAuthenticationState, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteUserAccount, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[Microsoft.Authentication.WebAssembly.Msal.Models.MsalProviderOptions, Microsoft.Authentication.WebAssembly.Msal, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext()
   at BforBoat.Web.Pages.Profile.OnInitializedAsync() in C:\Projects\vsts\mikaelsyska\bforboat\src\BforBoat.Web\Pages\Profile.razor.cs:line 29
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

image

( If, I can include the actual response from the IDP )

This is the response returned from Azure B2C …

I may be able to reproduce the issue on a minimal project if needed.

Yes please, that’d be much appreciated!

Thanks for the stack trace. I see the underlying System.Text.Json.JsonException: Invalid JSON is resolved (via backported #39075), but we still have the

Microsoft.JSInterop.JSException: An exception occurred executing JS interop: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 170.. See InnerException for more details.
 ---> System.Text.Json.JsonException: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 170.
 ---> System.InvalidOperationException: Cannot get the value of a token type 'Null' as a string.

error. Re-opening this issue.

I’ll send you the sample app as soon I’ve pushed on a public repos.

Hi @TanayParikh,

Do you have a more precise date for the release of Microsoft.AspNetCore.Components.WebAssembly.Authentication v6.0.2 ?

Thank you.

It was just released earlier today!

I also am having the exact same issue with B2C and Blazor WASM. Hope they release the fix soon. I’m hesitant to install preview builds.

Thanks Tanay for getting back to me. It’s unfortunate that the packages are not uploaded yet, as I’ve seen a number of issues fixed. I’ll probably wait for the release next month, if the pre release packages are not updated.