Failed Silent Auth in Blazor Wasm application

My Blazor Wasm application was running fine until a couple of weeks ago whereby I updated to .NET9.0 and likely also updated browers and such. Now I can’t authenticate, getting a NullReferenceException against the RemoteUserAccount in my AccountClaimsPrincipalFactory.

Upon investigation, I’ve noticed a Failed Silent Auth fills my Auth0 logs, and I’m not sure where to even begin looking.

note: I’ve noticed a new message in Chrome, but I don’t think this is the root of the issue, but it’s an observation none the less

Chrome is moving towards a new experience that allows users to choose to browse without third-party cookies.

Here is a redacted version of my appsettings

I setup my Oicd config as follows

	private static void ConfigureOidcAuthentication(WebAssemblyHostBuilder builder,
	                                                RemoteAuthenticationOptions<OidcProviderOptions> options)
	{
		builder.Configuration.Bind("Auth0", options.ProviderOptions);
		options.UserOptions.RoleClaim = builder.Configuration["Auth0:CustomClaimsSchema"] + "/roles";
		options.ProviderOptions.AdditionalProviderParameters.Add("audience", builder.Configuration["Auth0:Audience"]);
		options.ProviderOptions.ResponseType = "code";
	}

And I use an HttpRetryHandler to attempt token refresh, but as far as I can tell, the system doesn’t even get far enough to try a refresh.

	public async Task RefreshAccessToken()
	{
		var refreshUri = new Uri(_configuration.GetValue<string>(WellKnownConfigurationNames.Auth0.Authority));

		using var content = new MultipartFormDataContent();

		content.Add(new StringContent(WellKnownMultipartFormDataNames.REFRESH_TOKEN), WellKnownMultipartFormDataNames.GRANT_TYPE);
		content.Add(new StringContent(_configuration.GetValue<string>(WellKnownConfigurationNames.Auth0.ClientId)), WellKnownMultipartFormDataNames.CLIENT_ID);
		content.Add(new StringContent(await _storageService.GetRefreshToken().ConfigureAwait(false)), WellKnownMultipartFormDataNames.REFRESH_TOKEN);

		using var request = new HttpRequestMessage(HttpMethod.Post, refreshUri);
		request.Content = content;
		request.Headers.AddHeader(WellKnownHttpHeaders.CONTENT_TYPE, WellKnownDataContentMediaTypes.FormUrlEncoded);

		await _httpClient().SendAsync(request).ConfigureAwait(false);
	}

For the sake of completeness, here is one of the failed log messages

{
  "date": "2024-11-27T20:01:00.896Z",
  "type": "fsa",
  "description": "Login required",
  "client_id": "--redacted--",
  "client_name": "--redacted--portal",
  "ip": "--redacted--",
  "user_agent": "Chrome 131.0.0 / Mac OS X 10.15.7",
  "details": {
    "body": {},
    "qs": {
      "client_id": "--redacted--",
      "redirect_uri": "https://localhost:5000/auth/login-callback",
      "response_type": "code",
      "scope": "openid profile email offline_access",
      "state": "--redacted--",
      "code_challenge": "--redacted---v7E-62Ihh0",
      "code_challenge_method": "S256",
      "prompt": "none",
      "response_mode": "query",
      "audience": "https://--redacted--.app"
    },
    "connection": null,
    "error": {
      "message": "Login required",
      "oauthError": "login_required",
      "type": "oauth-authorization"
    },
    "riskAssessment": null
  },
  "hostname": "--redacted--.us.auth0.com",
  "audience": "https://--redacted--.app",
  "scope": [
    "openid",
    "profile",
    "email",
    "offline_access"
  ],
  "$event_schema": {
    "version": "1.0.0"
  },
  "log_id": "--redacted--",
  "tenant_name": "--redacted---test",
  "_id": "--redacted--",
  "isMobile": false,
  "originalData": {
    "date": "2024-11-27T20:01:00.896Z",
    "type": "fsa",
    "description": "Login required",
    "client_id": "--redacted--",
    "client_name": "--redacted---portal",
    "ip": "--redacted--",
    "user_agent": "Chrome 131.0.0 / Mac OS X 10.15.7",
    "details": {
      "body": {},
      "qs": {
        "client_id": "--redacted--",
        "redirect_uri": "https://localhost:5000/auth/login-callback",
        "response_type": "code",
        "scope": "openid profile email offline_access",
        "state": "--redacted--",
        "code_challenge": "--redacted---v7E-62Ihh0",
        "code_challenge_method": "S256",
        "prompt": "none",
        "response_mode": "query",
        "audience": "https://--redacted--.app"
      },
      "connection": null,
      "error": {
        "message": "Login required",
        "oauthError": "login_required",
        "type": "oauth-authorization"
      },
      "riskAssessment": null
    },
    "hostname": "--redacted--.us.auth0.com",
    "audience": "https://--redacted--.app",
    "scope": [
      "openid",
      "profile",
      "email",
      "offline_access"
    ],
    "$event_schema": {
      "version": "1.0.0"
    },
    "log_id": "--redacted--",
    "tenant_name": "--redacted---test",
    "_id": "--redacted--",
    "isMobile": false
  },
  "integrityRuleset": {},
  "id": "--redacted--"
}

Any assistance on getting to the bottom of this would be greatly appreciated

Hi @chase-cannect,

The failed silent auth error message is indicating you are trying to authenticate with the prompt=none query parameter but there isn’t an active session previously. Typically silent auth is used to re-authenticate without user interaction, and since there isnt an existing session, the error is thrown. This is justified by your Auth0 logs indicating a “Login required” error description. You can authenticate as usual by removing the prompt=none scope and then include it back in future requests.

Secondly, the Chrome deprecation warning about not using third-party cookies will require you to use either custom domains or Refresh Token Rotation to get new access tokens. (Reference: Third-party cookie deprecation in Chrome - #6 by tyf)

Thanks,
Rueben

Thank you for taking the time to answer.

I already had Refresh Tokens turned on, and I removed the default scope as you suggested, and after testing by removing offline_access, I got the same response.

1 Like

Hi @chase-cannect,

Thanks for the update.

I corrected my previous reply because the offline_accces scope is actually meant for getting refresh tokens.

I have just checked your logs and found that you were still performing silent auth, which happens when calling the prompt=none query parameter. Could you omit that query parameter and try again and let me know how it goes?
(Reference: Configure Silent Authentication)

Thanks,
Rueben