Azure AD B2C Microsoft.JSInterop.JSException: An exception occurred executing JS interop: The JSON value could not be converted to System.DateTimeOffset

anastasia 21 Reputation points
2022-04-28T13:09:50.807+00:00

I have a hosted Blazor WebAssembly app that is secured with Azure AD B2C. I need also to get some custom user attributes from an authenticated user via Graph API.
When I call the endpoint that needs authentication I get this error message in console:
197421-image.png

though everything looks good under network:
197346-image.png

The tokens I receive:
197405-image.png

It looks like there is an issue in converting expiration time to DateTime, but I'm not sure.

Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,385 questions
Microsoft Entra External ID
Microsoft Entra External ID
A modern identity solution for securing access to customer, citizen and partner-facing apps and services. It is the converged platform of Azure AD External Identities B2B and B2C. Replaces Azure Active Directory External Identities.
2,639 questions
Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
19,447 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 55,601 Reputation points
    2022-04-28T20:39:11.557+00:00

    you don't show your code, but it looks like you only have an B2C application id token, which can not be used to make a graph call.

    you should have authenticated with the required graph api scope, and gotten an id/refresh token that could be used to get a graph api access token via msal acquireTokenSilent()

    be sure the azure app was configured to allow Graph API access.

    note use website https://jwt.ms to decode the id and refresh tokens.

    0 comments No comments

  2. anastasia 21 Reputation points
    2022-04-29T08:03:48.107+00:00

    Hi and thank you for your answer
    My program.cs for the client:

    builder.Services.AddHttpClient("ServerAPI",
            client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
        .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
    
    builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("ServerAPI"));
    
    builder.Services.AddGraphClient("https://graph.microsoft.com/User.Read");
    
    builder.Services.AddMsalAuthentication(options =>
    {
        builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
        options.ProviderOptions.DefaultAccessTokenScopes.Add(
            "https://graph.microsoft.com/User.Read");
    
        options.ProviderOptions.LoginMode = "redirect";
    });
    

    GraphClientExtensions.cs:

    public static IServiceCollection AddGraphClient(
                this IServiceCollection services, params string[] scopes)
            {
                services.Configure<RemoteAuthenticationOptions<MsalProviderOptions>>(
                    options =>
                    {
                        foreach (var scope in scopes)
                        {
                            options.ProviderOptions.AdditionalScopesToConsent.Add(scope);
                        }
                    });
    
                services.AddScoped<IAuthenticationProvider,
                    NoOpGraphAuthenticationProvider>();
                services.AddScoped<IHttpProvider, HttpClientHttpProvider>(sp =>
                    new HttpClientHttpProvider(new HttpClient()));
                services.AddScoped(sp =>
                {
                    return new GraphServiceClient(
                        sp.GetRequiredService<IAuthenticationProvider>(),
                        sp.GetRequiredService<IHttpProvider>());
                });
    
                return services;
            }
    
            private class NoOpGraphAuthenticationProvider : IAuthenticationProvider
            {
                public NoOpGraphAuthenticationProvider(IAccessTokenProvider tokenProvider)
                {
                    TokenProvider = tokenProvider;
                }
    
                public IAccessTokenProvider TokenProvider { get; }
    
                public async Task AuthenticateRequestAsync(HttpRequestMessage request)
                {
                    var result = await TokenProvider.RequestAccessToken(
                        new AccessTokenRequestOptions()
                        {
                            Scopes = new[] {"https://graph.microsoft.com/User.Read"}
                        });
    
                    if (result.TryGetToken(out var token))
                    {
                        request.Headers.Authorization ??= new AuthenticationHeaderValue(
                            "Bearer", token.Value);
                    }
                }
            }
    
            private class HttpClientHttpProvider : IHttpProvider
            {
                private readonly HttpClient http;
    
                public HttpClientHttpProvider(HttpClient http)
                {
                    this.http = http;
                }
    
                public ISerializer Serializer { get; } = new Serializer();
    
                public TimeSpan OverallTimeout { get; set; } = TimeSpan.FromSeconds(300);
    
                public void Dispose()
                {
                }
    
                public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
                {
                    return http.SendAsync(request);
                }
    
                public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                    HttpCompletionOption completionOption,
                    CancellationToken cancellationToken)
                {
                    return http.SendAsync(request, completionOption, cancellationToken);
                }
            }