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.

Azure Active Directory
Azure Active Directory
An Azure enterprise identity service that provides single sign-on and multi-factor authentication.
14,690 questions
Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
975 questions
Azure Active Directory External Identities
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 35,791 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);
                }
            }