I'm about to go live with an app, and would, therefore, appreciate a review of my firebase authentication setup. I haven't been able to find many resources describing how to perform such authentication and most importantly securely using OWIN and ASP.NET 4.6. It's worthwhile to note that I've had some issues with resolving the SigningKeys (using an IssuerSigningKeyResolver
) and I really need to know if I've missed something important so authentication doesn't suddenly start to fail.
Before adding the resolver, authentication would fail after what seems to be 24 hours - probably because Google replaces their certificates and that the key used to sign the JWT token can't be found and validated. It seems to be working in its current state.
The method below is called during startup:
public static async void ConfigureAuth(IAppBuilder app)
{
const string validAudience = "MY-FIREBASE-PROJECT";
const string validIssuer = "https://securetoken.google.com/MY-FIREBASE-PROJECT";
const string openIdDiscoveryEndpoint = "https://securetoken.google.com/MY-FIREBASE-PROJECT/.well-known/openid-configuration";
var openidConfigManager = new ConfigurationManager<OpenIdConnectConfiguration>(openIdDiscoveryEndpoint);
var openidConfig = await openidConfigManager.GetConfigurationAsync();
var certificates = await GetGoogleCertificatesAsync();
var issuer = openidConfig.Issuer;
var tokens = openidConfig.SigningTokens;
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { validAudience },
Provider = new OAuthBearerAuthenticationProvider
{
OnValidateIdentity = OnValidateIdentity
},
IssuerSecurityTokenProviders = new[]
{
new OpenIdConnectCachingSecurityTokenProvider(
openIdDiscoveryEndpoint)
},
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "user_id",
RoleClaimType = ClaimTypes.Role,
IssuerSigningTokens = tokens,
ValidAudience = validAudience,
ValidIssuer = validIssuer,
IssuerSigningKeys = certificates.Values.Select(x => new X509SecurityKey(x)),
IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) =>
{
var updatedCertificates = GetGoogleCertificates();
return identifier
.Select(x => !updatedCertificates
.ContainsKey(x.Id)
? null
: new X509SecurityKey(updatedCertificates[x.Id]))
.First(x => x != null);
}
}
});
}
The following methods are used to fetch Google certificates.
public static async Task<Dictionary<string, X509Certificate2>> GetGoogleCertificatesAsync()
{
using (var http = new HttpClient())
{
var response = await http.GetAsync("https://www.googleapis.com/robot/v1/metadata/x509/[email protected]");
var dictionary = await response.Content.ReadAsAsync<Dictionary<string, string>>();
return dictionary.ToDictionary(x => x.Key, x => new X509Certificate2(Encoding.UTF8.GetBytes(x.Value)));
}
}
public static Dictionary<string, X509Certificate2> GetGoogleCertificates()
{
var task = Task.Run(async () => await GetGoogleCertificatesAsync());
return task.Result;
}
OpenIdConnectCachingSecurityTokenProvider
is used to fetch OpenId Connect metadata and SecurityTokens
. It can be found on GitHub here.
OnValidateIdentity
is only used to add custom roles/claims and is thus omitted.
Please, ask if you have any questions or feel that something is missing.