We have a Blazor Server app that requires authorization on all its components (internal business app):
// ...
app.UseHttpsRedirection();
app.MapStaticAssets(); // <-- Static files middleware before auth.
app.UseAuthentication();
app.UseAuthorization();
// ...
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.RequireAuthorization(); // <-- All pages require auth.
We also have a component in a Razor Class Library (RCL) that requires JavaScript to work. We've put it inside a .razor.js collocated file.
We are using a mix of Azure AD and Azure B2C in our auth flow (handled via OIDC), and our Routes.razor uses the <AuthorizeRouteView> component to render our pages/layouts.
Everything seemed to work fine, but we've hit an issue when the user's Blazor Server connection times out (i.e. they leave the app running in the background for 15-30 minutes).
We get this in the browser's logs (sensitive information redacted):
Access to script at 'https://login.microsoftonline.com/{OIDC URL parameters redacted}' (redirected from 'https://{site URL}/_content/{RCL}/Components/MyComponent.razor.js') from origin 'https://{site URL}' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Failed to load resource: net::ERR_FAILED
Error: Microsoft.JSInterop.Exception: Failed to fetch dynamically imported module: 'https://{site URL}/_content/{RCL}/Components/MyComponent.razor.js'
{Stack trace that shows it tried and failed to import module}
Information: Connection disconnected.
My understanding is that Blazor tries to reconnect, but it tries to access the collocated JavaScript file (which is apparently a protected resources despite our static assets middleware being configured before the authentication/authorization middleware) before actually renewing the auth.
This crashes (unhandled exception, Blazor's error ui pops-up) because it causes a redirect to our Azure AD/B2C setup, but that doesn't know how to handle our static assets, because they're not supposed to be protected resources (and we don't want to have to configure every single static asset in Azure).
This leads me to believe that maybe collocated JavaScript files are considered "a part of" their component as far as .RequireAuthorization() is concerned?
Am I missing something? I can't find anything in the documentation about collocated JavaScript files behaving differently with the authentication. In fact, the docs state this (Emphasis: mine):
[...] Blazor takes care of placing the JS file in published static assets for you.
Once the user refreshes the page, everything works as expected. So maybe it's something to do with how renewing a Blazor connection works? I'm honestly not sure why this is happening. Any help would be appreciated.
Edit: I've found that I am able to consistently reproduce the problem by clearing my cookies and running a GET request on the JavaScript file directly without logging in again. Since this works outside of a Blazor context, I'm thinking that the problem probably due to how Blazor adds its collocated files to the static assets.
.razor.jsfile is used to do things like input masking and CSS changes on the component (it's a wrapper around a third-party library). It doesn't do anything asynchronously or fetches on its own (unless I misunderstood and you meant that the Blazor JS was doing those).UseStaticFiles()can be configured with routing (and there's docs out there for how to handle auth with them), but I'm not sure how that'd work with Blazor's collocated JavaScript files. I'll try looking into that, just in case.