0

I'm having an issue where the token validation fails after some time (exactly when varies I think but usually counted in days). Restarting the app resolves the issue, so I think it's something wrong with how I initialize things.

I'm using Firebase and below is the bootstrapping code that runs at app startup. I read in a comment on this old post https://stackoverflow.com/a/29779351/611441 that Google rotates certs, so now I'm thinking that might be the issue? I'm only fetching the certs once for the lifetime of the application. If that's the case, how would I be able to refresh these every now and then since this only runs at startup?

public void ConfigureAuthentication(IAppBuilder app)
{
    var issuerSigningKeys = GetIssuerSigningKeys();
    var firebaseAdminProjectId = ConfigurationManager.AppSettings.Get("FirebaseAdminProjectId");
    app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions()
    {
        AuthenticationMode = AuthenticationMode.Active,
        AllowedAudiences = new[] { firebaseAdminProjectId },
        Provider = new OAuthBearerAuthenticationProvider
        {
            OnValidateIdentity = context =>
            {
                context.OwinContext.Set<bool>("OnValidateIdentity", true);
                return Task.FromResult(0);
            }
        },
        TokenValidationParameters = new TokenValidationParameters
        {
            IssuerSigningKeys = issuerSigningKeys,
            ValidAudience = firebaseAdminProjectId,
            ValidIssuer = ConfigurationManager.AppSettings.Get("FirebaseAdminValidIssuer"),
            IssuerSigningKeyResolver = (arbitrarily, declaring, these, parameters) => issuerSigningKeys
        }
    });


}

private static List<X509SecurityKey> GetIssuerSigningKeys()
{
    HttpClient client = new HttpClient();
    var task = client.GetStringAsync("https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"));
    task.Wait();
    string jsonResult = task.Result;

    //Extract X509SecurityKeys from JSON result
    List<X509SecurityKey> x509IssuerSigningKeys = JObject.Parse(jsonResult)
                        .Children()
                        .Cast<JProperty>()
                        .Select(i => BuildSecurityKey(i.Value.ToString())).ToList();

    return x509IssuerSigningKeys;
}

private static X509SecurityKey BuildSecurityKey(string certificate)
{
    //Removing "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" lines
    var lines = certificate.Split('\n');
    var selectedLines = lines.Skip(1).Take(lines.Length - 3);
    var key = string.Join(Environment.NewLine, selectedLines);

    return new X509SecurityKey(new X509Certificate2(Convert.FromBase64String(key)));
}

Anton
  • 1,346
  • 11
  • 31

1 Answers1

0

I think I've finally figured this out.

First of all, the signing keys seems to be rotated every 5 days because they have a validity property set with a date. This makes sense with the pattern I see...

However, I think the issue is in my code. The TokenValidationParameters' property IssuerSigningKeyResolver expects a delegate. But I'm getting the keys and assigning them to a variable which in turn is assigned to the property. So the "resolver" always resolves the initial keys returned. They'll never refresh. The fix is to simply assign the GetIssuerSigningKeys() method to the property instead:

IssuerSigningKeyResolver = (arbitrarily, declaring, these, parameters) => GetIssuerSigningKeys()
Anton
  • 1,346
  • 11
  • 31
  • I should add that this approach re-fetches the keys on every approach. So you probably want to cache the keys. – Anton Apr 23 '20 at 21:09