Search code examples
identityserver4

Identity Server 4 AddOidcStateDataFormatterCache does not apply to AddGoogle


When using the AddOidcStateDataFormatterCache method via:

services.AddOidcStateDataFormatterCache();

It only applies to providers which are added using

.AddOpenIdConnect();

Is there a way to apply the distributedCacheFormatter when using

.AddGoogle() 

Google is also an OpenId Provider and can be added using .AddOpenIdConnect or .AddGoogle, but using .AddGoogle doesn't use the state data formatter. I confirmed this by checking the redis cache (used as the underlying implementation of IDistributedCache) and saw a key created "DistributedCacheStateDataFormatter..." when using .AddOpenIdConnect, but nothing is created when using .AddGoogle.

I'm thinking this might be because .AddGoogle might use a different authentication handler which doesn't get picked up automatically by AddOidcStateDataFormatterCache


Solution

  • This is because the GoogleOptions class inherits from OAuthOptions and not OpenIdConnectOptions but they both have a ISecureDataFormat<AuthenticationProperties> StateDataFormat so you could re-use the DistributedCacheStateDataFormatter provided by identityserver4

    The post-configure class:

    internal class ConfigureGoogleOptions : IPostConfigureOptions<GoogleOptions>
    {
        private string[] _schemes;
        private readonly IHttpContextAccessor _httpContextAccessor;
    
        public ConfigureGoogleOptions(string[] schemes, IHttpContextAccessor httpContextAccessor)
        {
            _schemes = schemes ?? throw new ArgumentNullException(nameof(schemes));
            _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
        }
    
        public void PostConfigure(string name, GoogleOptions options)
        {
            // no schemes means configure them all
            if (_schemes.Length == 0 || _schemes.Contains(name))
            {
                options.StateDataFormat = new DistributedCacheStateDataFormatter(_httpContextAccessor, name);
            }
        }
    }
    

    And the registration helper (add this to your own static class):

    public static IServiceCollection AddGoogleStateDataFormatterCache(this IServiceCollection services, params string[] schemes)
    {
        services.AddSingleton<IPostConfigureOptions<GoogleOptions>>(
            svcs => new ConfigureGoogleOptions(
                schemes,
                svcs.GetRequiredService<IHttpContextAccessor>())
        );
        return services;
    }