I am trying to verify a json web token obtained by a firebase android client and passed to a server running .net
Following the answer here I created these methods to validate the token and extract the uid:
public static async Task<string> GetUserNameFromTokenIfValid(string jsonWebToken)
{
const string FirebaseProjectId = "testapp-16ecd";
try
{
// 1. Get Google signing keys
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://www.googleapis.com/robot/v1/metadata/");
HttpResponseMessage response = await client.GetAsync("x509/[email protected]");
if (!response.IsSuccessStatusCode) { return null; }
var x509Data = await response.Content.ReadAsAsync<Dictionary<string, string>>();
SecurityKey[] keys = x509Data.Values.Select(CreateSecurityKeyFromPublicKey).ToArray();
// Use JwtSecurityTokenHandler to validate the JWT token
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
// Set the expected properties of the JWT token in the TokenValidationParameters
TokenValidationParameters validationParameters = new TokenValidationParameters()
{
ValidAudience = FirebaseProjectId,
ValidIssuer = "https://securetoken.google.com/" + FirebaseProjectId,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = keys
};
SecurityToken validatedToken;
ClaimsPrincipal principal = tokenHandler.ValidateToken(jsonWebToken, validationParameters, out validatedToken);
var jwt = (JwtSecurityToken)validatedToken;
return jwt.Subject;
}
catch (Exception e)
{
return null;
}
}
static SecurityKey CreateSecurityKeyFromPublicKey(string data)
{
return new X509SecurityKey(new X509Certificate2(Encoding.UTF8.GetBytes(data)));
}
When I run the code I get the response:
{"IDX10501: Signature validation failed. Unable to match 'kid': 'c2154b0435d58fc96a4480bd7655188fd4370b07', \ntoken: '{"alg":"RS256","typ":"JWT","kid":"c2154b0435d58fc96a4480bd7655188fd4370b07"}......
Calling https://www.googleapis.com/robot/v1/metadata/x509/[email protected] does return a certificate with a matching id:
{
"c2154b0435d58fc96a4480bd7655188fd4370b07": "-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIRZGQCmoKoNQwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTYx\nMTIxMDA0NTI2WhcNMTYxMTI0MDExNTI2WjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAKHbxqFaNQyrrrv8gocpQjES+HCum8XRQYYLRqstJ12FGtDN\np32qagCbc0x94TaBZF7tCPMgyFU8pBQP7CvCxWxoy+Xdv+52lcR0sG/kskr23E3N\nJmWVHT3YwiMwdgsbWDIpWEbvJdn3DPFaapvD9BJPwNoXuFCO2vA2rhi1LuNWsaHt\nBj5jTicGCnt2PGKUTXJ9q1hOFi90wxTVUVMfFqDa4g9iKqRoaNaLOo0w3VgsFPlr\nMBca1fw1ArZpEGm3XHaDOiCi+EZ2+GRvdF/aPNy1+RdnUPMEEuHErULSxXpYGIdt\n/Mo7QvtFXkIl6ZHvEp5pWkS8mlAJyfPrOs8RzXMCAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBAJYXDQFIOC0W0ZwLO/5afSlqtMZ+lSiFJJnGx/IXI5Mi\n0sBI3QA7QXmiNH4tVyEiK+HsFPKAYovsbh7HDypEnBGsz9UmEU6Wn6Qu9/v38+bo\nLant6Ds9ME7QHhKJKtYkso0F2RVwu220xZQl1yrl4bjq+2ZDncYthILjw5t+8Z4c\nQW5UCr2wlVtkflGtIPR1UrvyU13eiI5SPkwOWPZvG2iTabnLfcRIkhQgIalkznMe\niz8Pzpk9eT8HFeZYiB61GpIWHG4oEb1/Z4Q//os+vWDQ+X0ARTYhTEbwLLQ0dcjW\nfg/tm7J+MGH5NH5MwjO+CI4fA3NoGOuEzF1vb7/hNdU=\n-----END CERTIFICATE-----\n"
I have successfully validated this token using the Java call (made in kotlin)
FirebaseAuth.getInstance().verifyIdToken(idToken).addOnSuccessListener { decodedToken ->
val uid = decodedToken.uid
}