aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

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

Open vsfeedback opened this issue 3 years ago • 54 comments

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] (https://aka.ms/dc/image?name=B61fe0ca32d5041f0acecb62eae0a3aa2637722914961548223_20211112-162455-image.png&tid=61fe0ca32d5041f0acecb62eae0a3aa2637722914961548223)

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

! [image.png] (https://aka.ms/dc/image?name=B3cf703b86356424eb56cb33bbf305263637722919619353128_20211112-163240-image.png&tid=3cf703b86356424eb56cb33bbf305263637722919619353128)


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)

vsfeedback avatar Jan 04 '22 21:01 vsfeedback

Thanks for contacting us. This is already fixed as part of #38962 / https://github.com/dotnet/aspnetcore/pull/39060.

mkArtakMSFT avatar Jan 10 '22 17:01 mkArtakMSFT

Please note, the fix for this issue should be available in the 6.0.2 patch release.

TanayParikh avatar Jan 10 '22 17:01 TanayParikh

Any estimates on this? I've got this installed 6.0.200-preview.21617.4 and still not working

rmencia-isv avatar Jan 17 '22 01:01 rmencia-isv

The fix for the underlying System.Text.Json.JsonException: Invalid JSON exception was backported through https://github.com/dotnet/aspnetcore/pull/39075.

@rmencia-isv could you please try this out using the latest installer available at https://github.com/dotnet/installer. Please let us know if you're still having the issue with that, and please provide the exact version of the dotnet sdk being used, along side the exact exception message you're getting.

TanayParikh avatar Jan 18 '22 15:01 TanayParikh

I have installed the latest versionfrom the url you provided (dotnet-sdk-6.0.200-preview.22068.4-win-x64.exe) and I still get the same error in Blazor wasm client app.

Checking the list I have this one installed (6.0.200-preview.22068.4) However, by looking at the call stack I see references to Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.1.0*

The error Message: 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.

InnerException: at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.Serialization.JsonConverter1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.InternalAccessTokenResult, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) at System.Text.Json.Serialization.JsonConverter1[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.InternalAccessTokenResult, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.1.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)'

rmencia-isv avatar Jan 19 '22 00:01 rmencia-isv

by looking at the call stack I see references to Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.1.0*

Ah that's definitely a bit strange. Could you please double check your csproj files to ensure you don't have any hardcoded versions which may be causing this issue? Also, if you could try adding the following to your nuget config:

<add key="dotnet6" value="https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet6/nuget/v3/index.json" />

Further details here.

TanayParikh avatar Jan 19 '22 04:01 TanayParikh

This is what I have in the project file. I also added the nuget in VS to get the packages from that place and no new updates available, even pre-release for any of those packages.

image

image

rmencia-isv avatar Jan 19 '22 04:01 rmencia-isv

Hey @rmencia-isv, I took a look at the feeds and you're right the 6.0.2 (prerelease) packages aren't up yet. You can either try waiting for the official 6.0.2 release (mid February), or try the 7.0 alpha packages (not sure if they'll be updated yet though).

TanayParikh avatar Jan 19 '22 16:01 TanayParikh

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.

rmencia-isv avatar Jan 19 '22 22:01 rmencia-isv

Hi, @TanayParikh ,

I'm facing the same issue. Unfortunately I cannot wit until mid February. Is there any chance to test the 6.0.2 (prerelease) you mentioned.

This is definitively not present on the repo you suggested...

kbeaugrand avatar Jan 26 '22 08:01 kbeaugrand

Hello @kbeaugrand, to test out the pre-release you can try using the nightly SDK & packages as above, or by using the 7.0 alpha/beta packages.

SDK Download: https://github.com/dotnet/installer (ensure you get the 6.0.2 or 7 alpha/beta SDK)

Add to your Nuget config:

<add key="dotnet6" value="https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet6/nuget/v3/index.json" />

Further details here.

TanayParikh avatar Jan 26 '22 18:01 TanayParikh

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.

Pete-Nago avatar Jan 27 '22 05:01 Pete-Nago

Hi @TanayParikh,

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

Thank you.

kbeaugrand avatar Feb 08 '22 10:02 kbeaugrand

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!

TanayParikh avatar Feb 09 '22 00:02 TanayParikh

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!

Thank you for your answer. I checked it, but unfortunately I'm still facing the issue... ;(

kbeaugrand avatar Feb 09 '22 16:02 kbeaugrand

unfortunately I'm still facing the issue

To confirm you've updated the SDK/.csproj to utilize the new 6.0.2 packages, correct? What exact error message are you seeing?

Can you please provide a minimal, public, github repro which reproduces this issue?

TanayParikh avatar Feb 09 '22 17:02 TanayParikh

unfortunately I'm still facing the issue

To confirm you've updated the SDK/.csproj to utilize the new 6.0.2 packages, correct? What exact error message are you seeing?

Can you please provide a minimal, public, github repro which reproduces this issue?

Hi,

Yes I confirm that I updated my package to 6.0.2 (https://github.com/CGI-FR/IoT-Hub-Portal/blob/main/src/AzureIoTHub.Portal/Client/AzureIoTHub.Portal.Client.csproj). I'm using OpenID connect.

You can find a public repos (not minimal) with my configuration here: https://github.com/CGI-FR/IoT-Hub-Portal/.

For the code sample, that is relevant, you can find at client Program.cs file the executed configuration: https://github.com/CGI-FR/IoT-Hub-Portal/blob/main/src/AzureIoTHub.Portal/Client/Program.cs.

The error message obtained is:

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: 170.. 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: 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.
   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.AspNetCore.Components.WebAssembly.Authentication.OidcProviderOptions, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=6.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext()
   at Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
   at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__13`1[[AzureIoTHub.Portal.Shared.Models.Device.DeviceListItem[], AzureIoTHub.Portal.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
   at AzureIoTHub.Portal.Client.Pages.Devices.DeviceListPage.LoadDevices() in C:\Users\beaugrandk\Source\Repos\CGI-FR\IoT-Hub-Portal\src\AzureIoTHub.Portal\Client\Pages\Devices\DeviceListPage.razor:line 179
   at AzureIoTHub.Portal.Client.Pages.Devices.DeviceListPage.OnInitializedAsync() in C:\Users\beaugrandk\Source\Repos\CGI-FR\IoT-Hub-Portal\src\AzureIoTHub.Portal\Client\Pages\Devices\DeviceListPage.razor:line 163
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
window.Module.s.printErr @ blazor.webassembly.js:1```

kbeaugrand avatar Feb 09 '22 17:02 kbeaugrand

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

kbeaugrand avatar Feb 09 '22 18:02 kbeaugrand

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 https://github.com/dotnet/aspnetcore/pull/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.

TanayParikh avatar Feb 09 '22 18:02 TanayParikh

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.

kbeaugrand avatar Feb 09 '22 18:02 kbeaugrand

I was so happy when I saw this should have been fixed.

Guess I will have to wait a little more with the auth implementation.

syska avatar Feb 25 '22 23:02 syska

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

kbeaugrand avatar Mar 30 '22 17:03 kbeaugrand

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

Hi @kbeaugrand, could you please confirm the Repo is still available and is public? I'm getting a 404 when I try to access that URL.

image

TanayParikh avatar Apr 05 '22 18:04 TanayParikh

My bad, it was private. Now it should be ok

kbeaugrand avatar Apr 05 '22 18:04 kbeaugrand

Thanks. Looks like it's an issue with the deserialization of the DateTimeOffset of the AccessToken here:

https://github.com/dotnet/aspnetcore/blob/ce10dcaa31b254bda5dcf854f5578f78418d412c/src/Components/WebAssembly/WebAssembly.Authentication/src/Models/AccessToken.cs#L16-L19

which is a part of

https://github.com/dotnet/aspnetcore/blob/ce10dcaa31b254bda5dcf854f5578f78418d412c/src/Components/WebAssembly/WebAssembly.Authentication/src/Services/RemoteAuthenticationService.cs#L246-L252

which gets called here:

https://github.com/dotnet/aspnetcore/blob/24280d974f0624002f963ef8607afe749f9d1b3e/src/Components/WebAssembly/WebAssembly.Authentication/src/Services/RemoteAuthenticationService.cs#L151

on the client side, this translates to:

https://github.com/dotnet/aspnetcore/blob/24280d974f0624002f963ef8607afe749f9d1b3e/src/Components/WebAssembly/Authentication.Msal/src/Interop/AuthenticationService.ts#L111-L123

which doesn't define AccessToken.Expires, which may be why the deserialization is failing.


For the non-MSAL case:

on the client side, this translates to:

https://github.com/dotnet/aspnetcore/blob/24280d974f0624002f963ef8607afe749f9d1b3e/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/AuthenticationService.ts#L98-L130

which gets the Expires via:

https://github.com/dotnet/aspnetcore/blob/24280d974f0624002f963ef8607afe749f9d1b3e/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/AuthenticationService.ts#L136-L140

Based on this, does Expires really need to be a DateTimeOffset vs. DateTime? cc/ @javiercn

TanayParikh avatar Apr 05 '22 18:04 TanayParikh

Related: https://stackoverflow.com/a/68565455/17995448

TanayParikh avatar Apr 05 '22 18:04 TanayParikh

Based on https://docs.microsoft.com/dotnet/standard/datetime/system-text-json-support we may be dealing with non compliant DateTimeOffset values.

Attempting to read non-compliant formats with Utf8JsonReader will cause it to throw a FormatException:

// Unhandled exception. System.FormatException: The JSON value is not in a supported DateTime format.

@kbeaugrand can you please confirm what needs to be done to trigger the exception you're seeing, using the repro you provided? I just end up with an Okta 404 when I try to run your project.

TanayParikh avatar Apr 05 '22 18:04 TanayParikh

@TanayParikh,

After configuring the OIDC settings for your tenant, and launching the project with Visual Studio, go to https://localhost:7002/fetchdata, you will have the issue present on log from the broswser developper console.

As a sample, you can verify my id_token that wahs provided by okta:

eyJraWQiOiI1YzlnblA3Wk1qbDY0NzdFTEl1VDlyNUpKYi0zLXhBNi04Q2x6akdWY0RJIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwMHU0Zm9xdmp0Rkd3c1lvajVkNyIsIm5hbWUiOiJkZW1vIGRlbW8iLCJsb2NhbGUiOiJlbl9VUyIsInZlciI6MSwiaXNzIjoiaHR0cHM6Ly9kZXYtMDc0NjEzMTAub2t0YS5jb20vb2F1dGgyL2RlZmF1bHQiLCJhdWQiOiIwb2E0Zm9yZTdqcGhLRDlHaTVkNyIsImlhdCI6MTY0OTE4ODc2NSwiZXhwIjoxNjQ5MTkyMzY1LCJqdGkiOiJJRC5vU2FlLVo1YWpjTXI3TW1OS3A5ckZCZVhLZi1uMUZCWG5uSEg1Y1FsTkd3IiwiYW1yIjpbInB3ZCJdLCJpZHAiOiIwMG80Zm0zeGV0NkRYQzVxZjVkNyIsIm5vbmNlIjoiZjU1NGE2ZjY3YTgxNDE3OWJhMzdlZmMxNWJhZDk4NWIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJrYmVhdWdyYW5kQGdtYWlsLmNvbSIsImdpdmVuX25hbWUiOiJkZW1vIiwiZmFtaWx5X25hbWUiOiJkZW1vIiwiem9uZWluZm8iOiJBbWVyaWNhL0xvc19BbmdlbGVzIiwidXBkYXRlZF9hdCI6MTY0ODY0ODk0NSwiYXV0aF90aW1lIjoxNjQ5MTg4NzY0fQ.aa5Cf5nHAm5QwcMaYgtCbU6Tnsub1H29AO-qtnFyOgzh_gY9oig1TxL-LwjiOB0nbMPODUF1Gkku90pAKql2j-zr5vGIoMN6886ZC8avMQn0ra-L6LFn00M_hNPJdWJCyXk9cUVsfkwoD6lqiiZHDDpuh4b59_R6DtLQl8jXES8i7jWiELLSXhe09tTMZy4COa0W6HxrMp2ahNXi954sFvHjkxZeXkpVrOCRUm0Lhzrm2M-hT2VaJ_YlTC78VUUI3eEOlBDqTCuBqyVrL8Q8IEk1tZs8y_LVsseMVkE6ho6kPCpHHdvc561XtmfvIkpVr4pFT8QIhVb7_Z8Jo6LfAw&state=797a8d10e2e647c09530765137eecd16

Don't worry, this doesn't give access to anything.. ;)

kbeaugrand avatar Apr 05 '22 19:04 kbeaugrand

@TanayParikh

Thanks. Looks like it's an issue with the deserialization of the DateTimeOffset of the AccessToken here:

https://github.com/dotnet/aspnetcore/blob/ce10dcaa31b254bda5dcf854f5578f78418d412c/src/Components/WebAssembly/WebAssembly.Authentication/src/Models/AccessToken.cs#L16-L19

which is a part of

https://github.com/dotnet/aspnetcore/blob/ce10dcaa31b254bda5dcf854f5578f78418d412c/src/Components/WebAssembly/WebAssembly.Authentication/src/Services/RemoteAuthenticationService.cs#L246-L252

which gets called here:

https://github.com/dotnet/aspnetcore/blob/24280d974f0624002f963ef8607afe749f9d1b3e/src/Components/WebAssembly/WebAssembly.Authentication/src/Services/RemoteAuthenticationService.cs#L151

on the client side, this translates to:

https://github.com/dotnet/aspnetcore/blob/24280d974f0624002f963ef8607afe749f9d1b3e/src/Components/WebAssembly/Authentication.Msal/src/Interop/AuthenticationService.ts#L111-L123

which doesn't define AccessToken.Expires, which may be why the deserialization is failing.

For the non-MSAL case:

on the client side, this translates to:

https://github.com/dotnet/aspnetcore/blob/24280d974f0624002f963ef8607afe749f9d1b3e/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/AuthenticationService.ts#L98-L130

which gets the Expires via:

https://github.com/dotnet/aspnetcore/blob/24280d974f0624002f963ef8607afe749f9d1b3e/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/AuthenticationService.ts#L136-L140

Based on this, does Expires really need to be a DateTimeOffset vs. DateTime? cc/ @javiercn

I think this doesn't comes from the deserialization of the access_token. In my configuration I only get the ID Token from the IDP. The issue occurs while getting the access token. at that time I have no network requests from the browser...

kbeaugrand avatar Apr 06 '22 17:04 kbeaugrand

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 ...

syska avatar Apr 06 '22 21:04 syska