Azure B2C token validation in API returns 401 Unauthorized due to invalid signature

I am trying to set up a web app and web API using Azure B2C as the auth mechanism, but apparently failing miserably. My web app and API are both registered in Azure, the return URIs set properly, a scope created for the API which is then granted to the app, an app client secret created, and I have tested this locally WITH IT WORKING, but now that I've published my API to my live Azure App Service, it goes wrong for some reason.

Locally, I have run my web API and web app separately, signed into the web app and then obtained an access token, called the API (running locally) and all works well. However, now the API is published and running live (i.e. https://api.myapp.net), I am running the web app locally, calling the live API and every single time I request an access token then send it to the API I get a 401 Unauthorized because apparently the signature is invalid. WHY?!?!?!?

Below are slightly redacted copies of my startup and app settings files. Note I also have Azure Front Door set up to redirect "login.myapp.net" to "myapp.b2clogin.com", this has been tested with both the user flows on the Azure dashboard and with my own app running locally and all is fine.

Here is my web app's Startup.cs file:

services.AddRazorPages();

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(Configuration.GetSection(Constants.AzureAdB2C))
    .EnableTokenAcquisitionToCallDownstreamApi(new string[] { "https://myapp.net/api/query" })
    .AddInMemoryTokenCaches();

services
    .AddControllersWithViews()
    .AddMicrosoftIdentityUI();

services
    .AddServerSideBlazor()
    .AddMicrosoftIdentityConsentHandler();

services.AddAuthorization(authorizationOptions =>
{
    authorizationOptions.AddPolicy(
        App.Policies.CanManageUsers,
        App.Policies.CanManageUsersPolicy());
});

services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    options.ResponseType = "code";
    options.SaveTokens = true;
}).AddInMemoryTokenCaches();

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<AppData>();

services.AddScoped<IAuthTokensService, AuthTokensService>();

services.AddOptions();

My web app's appsettings.json file:

"AzureAdB2C": {
    "Instance": "https://login.myapp.net",
    "ClientId": "my-web-app-client-id",
    "CallbackPath": "/signin-oidc",
    "Domain": "myapp.net",
    "SignedOutCallbackPath": "/signout",
    "SignUpSignInPolicyId": "B2C_1_SignUpIn",
    "ResetPasswordPolicyId": "B2C_1_PasswordReset",
    "EditProfilePolicyId": "B2C_1_ProfileEdit", 
    "ClientSecret": "my-client-secret"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"

Calling for an access token in my web app:

private readonly ITokenAcquisition _tokenAcquisition;

public AuthTokensService(ITokenAcquisition tokenAcquisition)
{
    _tokenAcquisition = tokenAcquisition;
}

/// <inheritdoc />
public async Task<string> GetToken()
{
    return await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { "https://myapp.net/api/query" });
}

My web API's Startup.cs file:

if (Configuration.GetConnectionString("SQLConnection") == null)
{
    throw new InvalidOperationException("ConfigureServices: Connection string 'SQLConnection' returned null.");
}


services.AddDbContext<MyAppDbContext>(
    option => option.UseSqlServer(Configuration.GetConnectionString("SQLConnection")));

services.AddMicrosoftIdentityWebApiAuthentication(Configuration, Constants.AzureAdB2C);

services.AddControllers();

services.AddScoped<IMyRepository, MyRepository>();

And my web API's appsettings.json file:

"AzureAdB2C": {
    "Instance": "https://login.myapp.net",
    "ClientId": "my-web-api-client-id",
    "Domain": "myapp.net",
    "SignUpSignInPolicyId": "B2C_1_SignUpIn",
    "SignedOutCallbackPath": "/signout/B2C_1_SignUpIn"
  },
  "ConnectionStrings": {
    "SQLConnection": "Server=(localdb)\\mssqllocaldb;Database=MyAppDebug;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }

Can anybody advise on why this is? The only sensible answer I've seen anywhere online is that Blazor uses a v1.0 endpoint to obtain public keys whereas v2.0 is required for the API (see here) and I can see this happening with my tokens, but when I followed the fix given on the Microsoft documentation, I then get an exception thrown on startup of my web app IDX20807: Unable to retrieve document from: 'System.String'.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum