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