Don328
Don328

Reputation: 201

Blazor wasm hosted 'Could not load settings from configuration/TestApp.Client - (AuthenticationService.js)

Issue Summary


Setup

Boilerplate Blazor hosted wasm app with Authentication using: dotnet new blazorwasm -ho -au Individual -o TestApp

I changed the default database to use MySql

I ran the application on my development machine and tested that I could create users, login, etc. Everything works fine in my development environment.

After deploying site loads, but shows 'Authorizing' at the top of the main body and throws the 'Unhandled error has occured' message at the bottom of the browser along with the error messages in the browser console as shown below


Deployment

Server environment

Raspberry Pi4(8gb) running Ubuntu Server 20.04 (64bit) with Apache2

Deployment method

After pushing changes to Github, I do a fetch and a pull in a remote repo on my server

I then make sure the project builds and publish to /var/www/[MyWebAddress]/TestApp using: dotnet publish -o /var/www/[my web address]/TestApp --no-self-contained -r linux-x64

I copied my apache site conf file ([my web address].conf) straight from Microsoft docs:

<VirtualHost *:80>
    ServerName www.[my web address]
    ServerAlias *.[my web address]

    DocumentRoot "/var/www/[my web address]/TestApp"
    ErrorDocument 404 /wwwroot/index.html

    AddType application/wasm .wasm
    AddType application/octet-stream .dll

    <Directory "/var/www/[my web address]/TestApp">
        Options -Indexes
        AllowOverride None
    </Directory>

    <IfModule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/css
        AddOutputFilterByType DEFLATE application/javascript
        AddOutputFilterByType DEFLATE text/html
        AddOutputFilterByType DEFLATE application/octet-stream
        AddOutputFilterByType DEFLATE application/wasm
        <IfModule mod_setenvif.c>
        BrowserMatch ^Mozilla/4 gzip-only-text/html
        BrowserMatch ^Mozilla/4.0[678] no-gzip
        BrowserMatch bMSIE !no-gzip !gzip-only-text/html
    </IfModule>

Troubleshooting insights

Prior to trying this setup, I did an identical deployment, but didn't use authentication or a database connection. I just deployed a boilerplate Blazorwasm hosted app using the same method described above and tested it on the server. Everything worked including the FetchData and Counter pages. This makes me pretty sure that my deployment method works and that it is something to do with IdentityServer that is causing the issue.

In order to test this, I am using my laptop connected to a wireless hotspot served from my phone. This allows me to access my local server from an external network (just using my phone with the wifi disabled works, but I can't open the browser tools for troubleshooting on a mobile device). I'm getting slightly different errors from different browsers but they are similar to these that were produced by Firefox:

Error: "Failed to start platform. Reason: AbortError: The operation was aborted. "
    v https://[my web address]/ framework/blazor.webassembly.js:1
    u https://[my web address]/ framework/blazor.webassembly.js:1
    u https://[my web address]/ framework/blazor.webassembly.js:1
    u https://[my web address]/ framework/blazor.webassembly.js:1
AbortError: The operation was aborted.
crit: Microsoft.AspNetCore.Components.WebAssembly.REnderingWebAssemblyREenderer[100]
      Unhandled exception rendering component: Could not load settings form '_configuration/TestSite.Client'
      createUserManager@https://[my web address]/ content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js:1:5893

[ continued error messages omitted ]

I wouldn't be the least bit surprised if this is the result of a very basic mistake, but I also wouldn't be surprised if I have some critical piece that isn't compatible with what I'm trying to do. I'm just learning, so please don't assume that I have done all of the obvious stuff. It may not be that obvious to me.



Progress

From the link provided by Pavel Voronin in the comment below, I found a solution that solves the initial problem:

From Github issues

In my case the error showed up even when I started the server project. My Identity Server is not installed on the same server where my app is located.

So, I made some changes in Program.cs (client)

public static async Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("app");
    builder.Services.AddHttpClient("BlazorApp1.ServerAPI", client =>  
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
        .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
    builder.Services.AddTransient(sp => 
        sp.GetRequiredService<IHttpClientFactory>() 
        CreateClient("BlazorApp1.ServerAPI"));
    //The following line has been disabled
    //builder.Services.AddApiAuthorization();
    //In order to authenticate to IS4:
    builder.Services.AddOidcAuthentication(options =>
    {
        builder.Configuration.Bind("Local", options.ProviderOptions);
    });

await builder.Build().RunAsync();
}

Also I configure the OpenId settings in appsettings.json with Authority and ClientId. After this changes, the error disappeared.

Not sure if it's the solution to this error.

After making the changes to the Program file, the page loads as expected without errors

But when I click on the 'Register' link, there is a brief 'Registration is not supported' message before a redirect back to the index page


After poking around a bit more, I don't believe this to be a solution and I'm rolling it back

From the example quoted above:

My Identity Server is not installed on the same server where my app is located.

This led him to use OIDC instead of ApiAuthentication. This isn't the case for me because my Authentication lives on the Blazor server application that is part of the Blazor 'hosted' template which essentially acts as the api for the project

One thing I didn't include in my description of my deployment workflow was that I migrate and update the database on the server after pulling from GitHub and building the project in the server repo, just before publishing. I have verified that the database is created and all of the Auth tables exist on the server db

I also had a theory that it was launching using IIS setting on the server. The tests I was doing in development were using Kestrel. I launched from Visual Studio using IIS and got some similar errors to what I was seeing from the server. So I deleted all of the IIS configuration from the both launchsettings.json files and re-published. No change in behavior


What I think I have narrowed out


I'm pretty sure It has something to do with configuring Identity Server.

Upvotes: 6

Views: 6178

Answers (2)

34gl3
34gl3

Reputation: 41

The IdentityServer configuration in appsettings.json should look similar to the following

  "IdentityServer": {
    "Clients": {
      "MyProject.Client": {
        "Profile": "IdentityServerSPA"
      }
    },
    "Key": {
      "Type": "Store",
      "StoreName": "My",
      "StoreLocation": "CurrentUser",
      "Name": "CN=my-project"
    }
  },

so the OidcConfigurationController will be able to find your client id.

Upvotes: 4

juvivas
juvivas

Reputation: 41

AddOidcAuthentication call OidcConfigurationController to manage authtoization task and this controller use AuthenticationService.js you need set the controller to allow anonymous request to work correctly

 [AllowAnonymous]
public class OidcConfigurationController : Controller
{
    private readonly ILogger<OidcConfigurationController> _logger;

    public OidcConfigurationController(IClientRequestParametersProvider clientRequestParametersProvider, ILogger<OidcConfigurationController> logger)
    {
        ClientRequestParametersProvider = clientRequestParametersProvider;
        _logger = logger;
    }

    public IClientRequestParametersProvider ClientRequestParametersProvider { get; }

    [HttpGet("_configuration/{clientId}")]
    public IActionResult GetClientRequestParameters([FromRoute] string clientId)
    {
        var parameters = ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId);
        return Ok(parameters);
    }
}

Upvotes: 4

Related Questions