0

I'm experiencing a caching issue with Refit when calling Keycloak Admin API endpoints. Despite setting various no-cache headers and implementing a custom HttpMessageHandler, I'm still getting cached responses from previous requests.

Problem Description

When I create a new realm in Keycloak and immediately call the RealmsAll() method, it returns the old cached list (e.g., 5 realms instead of 6). However:

  • Direct HttpClient calls work correctly (no caching)
  • Postman requests work correctly
  • Restarting the application and calling RealmsAll() returns the correct response

This suggests the issue is client-side caching within Refit, not server-side.

Same problem occurs on ClientsAll3() method also.

Current Setup

Refit Interface:

[Headers("Accept: application/json")]
[Get("/admin/realms")]
Task<IApiResponse<ICollection<RealmRepresentation>>> RealmsAll([Query] bool? briefRepresentation);

Service Registration

services.AddTransient<NoCacheHandler>();
var refitSettings = new RefitSettings
{
    ContentSerializer = new SystemTextJsonContentSerializer(new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = false,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    })
};

services.AddRefitClient<IKeycloakAdminRESTAPI>(refitSettings)
    .AddHttpMessageHandler<KeycloakAdminAuthenticationHandler>()
    .AddHttpMessageHandler<NoCacheHandler>()
    .ConfigureHttpClient((serviceProvider, config) =>
    {
        var keycloakOptions = serviceProvider.GetRequiredService<IOptions<KeycloakOptions>>();
        config.BaseAddress = new Uri(keycloakOptions.Value.Url);
        
        config.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue
        {
            NoCache = true,
            NoStore = true,
            MustRevalidate = true,
            MaxAge = TimeSpan.Zero
        };
        config.DefaultRequestHeaders.Pragma.ParseAdd("no-cache");
    });

Custom NoCacheHandler:

public class NoCacheHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Add no-cache headers
        request.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
        request.Headers.Add("Pragma", "no-cache");
        
        // Add unique timestamp to URL
        var uriBuilder = new UriBuilder(request.RequestUri);
        var query = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
        query["_t"] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
        uriBuilder.Query = query.ToString();
        request.RequestUri = uriBuilder.Uri;

        var response = await base.SendAsync(request, cancellationToken);
        
        // Clear response cache headers
        response.Headers.Remove("ETag");
        response.Headers.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue
        {
            NoCache = true,
            NoStore = true,
            MustRevalidate = true
        };

        return response;
    }
}

What I've Tried
Added Cache-Control: no-cache, no-store, must-revalidate headers Added Pragma: no-cache headers Added unique timestamp query parameter to each request Removed ETag headers from responses Configured HttpClient with no-cache settings Used custom HttpMessageHandler to modify requests/responses Set ConnectionClose = false and other HttpClient configurations

I've tried disabling caching on client side on Refit. Also tried HttpClient. Refit didn't worked as expected but HttpClient did.

Environment .NET 8 Refit 8.0.0 Keycloak Admin REST API Windows development environment

5
  • Postman is very robust and automatically add HTTP Headers to the message while c# does not. Usually this can be fixed by adding the same HTTP headers that are added with Postman. To see the complete Postman message go to Postman Control Panel and view the Raw HTTP message. Commented Jul 22 at 12:08
  • There is no issue with C#'s HttpClient, the problem occurs only with Refit. Commented Jul 22 at 12:49
  • What type of authentication are you using? Doesn't look like you are using OAUTH2 in code above. Keycloak uses OAUTH2. See keycloak.org/docs/latest/release_notes/index.html Commented Jul 22 at 17:06
  • We are fetching token via client_credentials grant type. We created a special client that has many roles and authorization. We added a DelegatingHandler just like NoCacheHandler for this token purposes. You can see we added it to RefitClient on service registration with this line : '.AddHttpMessageHandler<KeycloakAdminAuthenticationHandler>()' Commented Jul 23 at 6:47
  • It must be a cookie issue. See keycloak.org/docs/latest/release_notes/… Commented Jul 23 at 9:36

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.