Cross-origin redirection denied by CORS policy: Cancelled load because it violates the resource's CORS response header

Greetings,

I am trying to implement cross-origin isolation for my web app, and am running into a quagmire in the process. I’ve set the headers in my VirtualHost in Apache properly, and have confirmed that cross-origin isolation is running. However, this has caused a conflict with my Auth0 implementation - specifically, I’ve started getting the message in the Subject of this topic.

I deduced that the probably cause was that I was changing domain from my app’s domain to my Auth0 domain (“dev-…”). I therefore set up a custom domain which matched my app’s domain name. Once this was in place, I tested and found that I got the same error, with the custom domain in place of the original Auth0 domain.

My suspicion is that I forgot to configure something (or things), but I’m not sure what. Please advise.

Thanks!

Addendum: Refreshing the page continues execution and brings up the Universal Login correctly.

Hi @david42

I am sorry about the delayed response to your inquiry regarding the matter!

Are you using loginWithPopup by any chance in your application? If you are, I believe the issue might be caused due to the strict same origin CORS policy which might sever the communication link on which the Auth0’s loginWithPopup relies on when enabling CO Isolation. In this situation, using a custom domain will not fix the issue because even if the both domains would be Same Site but not Same Origin.

I would recommend to change your configuration in order to use same-origin-allow-popups instead of same-origin OR to use loginWithRedirect instead if possible.

If you have any other questions or still experience issues with this, let me know!

Kind Regards,
Nik

Hi Nik,

Well, no. I’m not usingloginWithPopup,at least not explicitly.

However, an additional detail is worth mentioning - I found that if after I got the error message I refreshed the page, execution continues and I get the proper Auth0 login dialog, as if nothing was wrong.

The net effect is that this error doesn’t freeze further development, but is an unacceptable problem in production which needs to be addressed.

Any thoughts?

David

Got it!

Do you use any kind of wildcard entries for domains in your CORS configuration as such:

Access-Control-Allow-Origin: *

If you do, could you please try changing the values to something specific to see if it impacts the behaviour in any way? Also, for the Access-Control-Allow-Credentials header, did you set it to true or false?

Also, do you check or handle the login using resources which resolve during an iframe such as checkSession which would lack the initial isolation headers which would then properly be sent after a refresh?

Kind Regards,
Nik

Hi Nik,

I have the following headers in my configuration related to CORS:

Cross-Origin-Opener-Policy "same-origin"
Cross-Origin-Embedder-Policy "require-corp"

Neither.

No.

David

Hi Nik,

So, after some research, I think I found the issue, but I’m also between a rock and a hard place…

On the one hand, I need the headers I mentioned above in order to implement cross-origin isolation for this site. On the other hand, same-origin requires that everything resolves to “www.fotlr.org” (my site name) while my custom domain is “login.fotlr.org”, which isn’t a match. Furthermore, unless I’m mistaken, I can’t have a custom domain “www.fotlr.org” because the CNAME would conflict with the site’s name. Or would it?

Thanks,

David

Thanks for the extra information @david42

After some research, as you have mentioned, you will not be able to use a custom domain for www.forlt.org on Auth0 since you would be required to use a subdomain (such as login or auth).

I believe you should be able to resolve the issue while still keeping CO Isolation by having SharedArrayBuffer enabled, making sure you initialize any login calls with loginWithRedirect and enabling Refresh Tokens while using the local storage.

The standard silent authentication would be using an iFrame which can be blocked by your require-corp header. If you are initializing your login call with loginWithRedirect and you have already configured the things mentioned above, please let me know what kind of application you are using for your CO Isolation and how you have configured your Auth0 SDK within the application.

Kind Regards,
Nik

Hi Nik,

Hmm… The objective, obviously, is to enable SharedArrayBuffer. The specific reason is that the site in question involves an embedded Zoom Client, and enabling SharedArrayBufferhelps the Zoom Client function properly.

If there is another way to enable this, without the CORS conflict, I’d like to know how. I’m afraid the rest of your suggestions read foreign to me, so any references or walkthroughs would be greatly appreciated.

David

Got it, I will be looking further into that.

Could you please let me know what kind of SDK are you using in order to provide accurate information on the implementation?

Kind Regards,
Nik

Hi Nik,

I’m not sure whether you’re asking about the Zoom SDK or the Auth0 SDK… For Zoom, I’m currently using their Meeting SDK for Web, which involves some JavaScript..

The Auth0 implementation is from the NuGet package “Auth0.AspNetCore.Authentication” v.1.5.1.

David

Hi again!

Since you are using AspNetCore authentication, you can initialize the service to use Refresh Tokens like this:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddAuth0WebAppAuthentication(options =>
        {
            options.Domain = Configuration["Auth0:Domain"];
            options.ClientId = Configuration["Auth0:ClientId"];
            options.ClientSecret = Configuration["Auth0:ClientSecret"];
        })
        .WithAccessToken(options =>
        {
            options.Audience = Configuration["Auth0:Audience"];
            options.UseRefreshTokens = true;
        });
}

You will also need to enable offline access for your API by going to the Auth0 Dashboard → Applications → APIs → Allow Offline Access. Once this is enabled, you application will need to pass int he additional offline_access scope during authentication.

Could you provide me a sample of how are you handling the login and redirection inside the application which is triggering the CORS error so I can take a better look and understand the implementation?

Let me know if that helps with the CORS issue or not.

Kind Regards,
Nik

Hi again!

Since you have not responded back for some time regarding the issue, I will be marking the previous reply as the solution. If the issue still, persists, please leave a reply before the topic closes or post a new one referencing this one.

Kind Regards,
Nik

Hi Nik,

Still persisting. I had spoken to Lily Wisecarver on the matter, and she thinks that the problem stems from the fact that the link that call my login method is a NavLink, not a regular anchor.

That addition of the code that you gave did not run, but that may be attributed to the fact that I could not find the “Allow Offline Access” switch in the location specified.

David

I see. Thanks for the update. That indeed may be a possibility.

The setting that I mentioned is located under the Auth0 Dashboard → Applications → APIs → Your_API-> Access Settings → Allow Offline Access. It should be located at the very end of the settings under the Settings tab of your registered API.

Kind Regards,
Nik

Hi Nik,

I have enclosed three screenshots. One is a list of the APIs I have available, one is the settings under Management API, and one is the settings I have under My Account API. The setting you illustrated above is not to be found in either API. Do I have something set up incorrectly?

David

Alright, sorry if I was not clear enough previously since the Management API and My Account API would not have that setting available because it is only available for a registered external API.

Basically, you would need to have an API created within your application for M2M communications with Auth0 if necessary. If your current implementation does not require one, you could just configure an API within your application in order to register it within the Dashboard and enable the Offline Access setting to see if the configuration provided above fixes the CORS issue with the help of refresh tokens and audience.

Again, as you have stated in your previous message, the fact that the Zoom SDK window is embedded within the application as a NavLink and not actually anchored, it may cause any communications or request between it and your application to be considered third party since they have a different origin then the one expected.

I will try to find some more clarifications regarding the issue and see if there are any immediate fixes we can provide regarding the matter, however, this seems to be a configuration issue. You can also try opening an issue on the SDKs Github page to see if any of the engineers have some insight on the matter.

Kind Regards,
Nik

I’m using API calls in my application. So, you’re suggesting that I create a third API, configure it, and find the setting in there?

I’m not sure how the Zoom SDK plays into the problem, aside from needing Shared Array Buffer = true to operate at its best.

I’ve appended my program.cs as a reference - hopefully, that will provide some data for you. Meanwhile, I’ll create the third API and see how that goes.

Thanks for all your help so far,

David

using Festival.Data;
using Festival.Components;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.HttpOverrides;
using Auth0.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContextFactory<ScheduleDbContext>((sp, options) =>
{
    var env = sp.GetRequiredService<IWebHostEnvironment>();
    var dbPath = Path.Combine(env.ContentRootPath, "Schedule.db");
    options.UseSqlite("DataSource=" + dbPath);
});

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

var myAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
    options.AddPolicy(myAllowSpecificOrigins, policy =>
    {
        policy.WithOrigins(new []
            {
                "https://*.fotlr.org" 
            })
            .AllowAnyMethod()
            .AllowAnyHeader();
    });
});

builder.Services.AddScoped<RefreshableAuthStateProvider>();

var config = builder.Configuration;
builder.Services.AddAuth0WebAppAuthentication(options =>
{
    IConfigurationSection auth0AuthSection = config.GetSection("Authentication:Auth0");
    options.Domain = auth0AuthSection["Domain"];
    options.ClientId = auth0AuthSection["ClientId"];
    options.ClientSecret = auth0AuthSection["ClientSecret"];
    options.Scope = "openid profile email";

    AppConstants.Auth0Audience = auth0AuthSection["Audience"];
    AppConstants.Auth0ApiDomain = auth0AuthSection["Domain"];
    AppConstants.Auth0ClientId = auth0AuthSection["ClientId"];
    AppConstants.Auth0ClientSecret = auth0AuthSection["ClientSecret"];
    
    IConfigurationSection mailSection = config.GetSection("Authentication:Mail");
    AppConstants.MailApiDomain = mailSection["Domain"];
    AppConstants.MailApiKey = mailSection["ApiKey"];
    
    options.OpenIdConnectEvents = new OpenIdConnectEvents
    {
        OnTokenValidated = async context =>
        {
            var user = context.Principal;

            var optionsBuilder = new DbContextOptionsBuilder<ScheduleDbContext>();
            optionsBuilder.UseSqlite("DataSource=./Schedule.db");
            await using var dbContext = new ScheduleDbContext(optionsBuilder.Options);
            using var auth = new RefreshableAuthStateProvider();
            var after = new AfterLogin(dbContext, auth);
            after.UpdateUserInfo(user);
        }
    };
});

var zoomAuthSection = config.GetSection("Authentication:Zoom");
AppConstants.ZoomClientId = zoomAuthSection["ClientID"];
AppConstants.ZoomClientSecret = zoomAuthSection["ClientSecret"];

builder.Services.AddBlazorBootstrap();
builder.Services.AddDevExpressBlazor(options =>
{
    options.SizeMode = DevExpress.Blazor.SizeMode.Small;
});

builder.Services.AddServerSideBlazor().AddCircuitOptions(options =>
{
    options.DetailedErrors = true;
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.Use(async (HttpContext context, Func<Task> next) =>
{
    context.Response.Headers.Append("Cross-Origin-Embedder-Policy", "require-corp");
    context.Response.Headers.Append("Cross-Origin-Opener-Policy", "same-origin");
    await next();
});
app.UseCors(myAllowSpecificOrigins);

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseWebSockets();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();

app.UseAntiforgery();
app.UseStaticFiles();

app.MapStaticAssets();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

app.MapGet("account/login", async (HttpContext context, string returnUrl = "/") =>
{
    var authenticationProperties = new LoginAuthenticationPropertiesBuilder()
        .WithRedirectUri(returnUrl)
        .Build();
    await context.ChallengeAsync(Auth0Constants.AuthenticationScheme, authenticationProperties);
});

app.MapGet("account/logout", async (HttpContext context) =>
{
    var authenticationProperties = new LogoutAuthenticationPropertiesBuilder()
        .WithRedirectUri("/")
        .Build();
    await context.SignOutAsync(Auth0Constants.AuthenticationScheme, authenticationProperties);
    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
});

app.Run();

Hi.
Your program.cs file indeed looks fine and I cannot see anything wrong with it at this time.

I have checked your tenant and could you please confirm if you have enabled Allow Cross Origin Authentication under your Application? This can be found under Cross-Origin Authentication section. I am not sure if I have checked the right application, however, the one I have checked seemed to have it disabled.

If it is indeed disabled, could you please enable it and add any necessary Allowed Origins in the list then set the Cross-Origin-Opener-Policy to same-origin-allow-popus to see any change in behaviour or errors regarding the matter?

Otherwise, as far as I have investigated, the related error might be caused by a pop-up or iframe which is being opened in your application causing the cross-origin isolation to trigger.

Looking forward to your update!

Kind Regards,
Nik

Hi Nik,

I’ve enabled Allow Cross Origin Authentication on every application in the tenant, and added the entry “https://*.fotlr.org” to all of them. in Allowed Origins. Additionally, I created an API so that Offline Access could be enabled, also making the code changes to allow for refresh tokens.

Still nothing.

In the process of figuring this out, I think I’ve lost focus on the core system requirements involved. I’m looking. for the most straightforward way of implementing them. Here are the requirements:

  1. Auth0 authentication, with occasional API calls (primarily for Roles)
  2. Support for the Zoom Video SDK
    1. to support this, cross-origin isolation is required.

I’m making the assumption that there is a way to implement both requirements and that using a custom domain in Auth0 is the approach. I have set up the domain and am still getting CORS issues. Note that the issue resolves on one of two conditions:

  1. the user refreshes the page after the call to Auth0 (either login or logout).
  2. the user disables CORS error in their browser (a security risk).

Neither of these are acceptable/ I would like the same workflow as I had before adding the CORS headers - that is, the user clicks on Login and immediately sees the Auth0 dialog.

Is this possible? if so, how to implement this, in the cleanest possible way? I suspect that it’s a settings problem, not a code problem.

Thanks you for your help and patience,

David

Hi again @david42

Thanks for the update.

For the custom domain that you have set up, are you using Auth0 Managed Custom Domain or are you using a Self-Managed Custom Domain?
I would recommend using a self managed one with a reverse proxy so that you can try configuring it to inject the headers into the responses coming from Auth0.

Otherwise, can you let me know how are you triggering your login in your frontend code?
I believe that if you are using an onClick handler or NavigationManager.NavigateTo without forcing a load might be a cause for the CORS issue that you are receiving.
Can you check if your frontend uses a standard HTML anchor tag or a direct link to the required login endpoint?

window.location.href = '/Account/Login';

//OR

//These should be able to hit your MapGet endpoint by forcing a request to the server
<a href="/Account/Login">Log In</a>
//OR
<a href="account/login?returnUrl=/">Log In</a>

I completely understand your frustration regarding the matter, as I have mentioned and researched regarding this CORS issue, it could be triggered by a pop-up login flow which is missing the required headers or cookies.Most probably that is why when you refresh the page, the popup interaction is considered finished and if the user successfully logged in during the popup (despite the error in your app), the Auth0 session cookie was set.

Looking forward to your next update!

Kind Regards,
Nik