I have an issue that I'm now completely at a loss over.
I have an authentication server that creates and sends JWT's to a unity application (android/VR).
The auth server creates a token as such
private string GenerateJwtToken(User user)
{
var symmetricKey = Convert.FromBase64String(_tokenSettings.Secret);
var expires = DateTime.Now.AddMinutes(Convert.ToInt32(15));
var tokenHandler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.PrimarySid, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.GivenName, user.FirstName),
new Claim(ClaimTypes.Surname, user.LastName),
new Claim("company", user.Company),
new Claim(ClaimTypes.Role, "api_user"),
new Claim(ClaimTypes.Expiration, $"{expires.ToShortDateString() + " " + expires.ToShortTimeString()}"),
}),
Expires = expires,
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(symmetricKey),
SecurityAlgorithms.HmacSha256Signature)
};
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(securityToken);
return token;
}
I have no issues decoding this and getting out the claims in a console application. This is where the confusion comes in. When I try and perform the same task in Unity and build the application to the VR headset, I'm met with issues, namely this
"IDX10729: Unable to decode the header 'header' as Base64Url encoded string. jwtEncodedString: 'Token here'."
The unity auth service looks like this
public async Task<string> GetAccessToken(string username, string password)
{
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage())
{
//TODO: Replace this hardcoded URL value here.
request.RequestUri = new Uri("{{URL Emmited}}");
request.Method = HttpMethod.Post;
var body = new AuthRequest()
{
Username = username,
Password = password
};
var content = new StringContent(JsonConvert.SerializeObject(body), encoding: Encoding.UTF8, "application/json");
request.Content = content;
var response = await client.SendAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
var tokenContent = JsonConvert.DeserializeObject<Response>(responseContent);
var token = tokenContent.Token;
return token;
}
}
}
and retrieving the claims, I've tried two different ways
public string GetUserName(string token)
{
try
{
var securityToken = new JwtSecurityToken(token);
return securityToken?.Claims.First(claim => claim.Type == "given_name").Value;
}
catch (Exception exception)
{
//log exception here
return string.Empty;
}
}
and
public string GetUserName(string token)
{
try
{
var handler = new JwtSecurityTokenHandler();
var securityToken = handler.ReadJwtToken(token);
return securityToken?.Claims.First(claim => claim.Type == "given_name").Value;
}
catch (Exception exception)
{
//log exception here
return string.Empty;
}
}
ReadJwtToken internally just creates a new JwtSecurityToken object so I assume there's something in that I'm missing.
Both of these throw the same "Unable to decode the header 'header' as Base64Url encoded string" error, however, if I do handler.CanReadToken(token); this returns true, which baffles me even more.
Anyone have any ideas as to why this is happening and any clues on how to fix it.
some further information; the token I retrieve can be decoded in JWT.io and in a console app, I'm using the dotnet standard 2.0 assemblies for System.IdentityModel, System.IdentityModel.Tokens.JWT, System.IdentityModel.Tokens, System.IdentityModel.Logging and Newtonsoft.Json
Related
I don't understand how this library works. Could you help me please ?
Here is my simple code :
public void TestJwtSecurityTokenHandler()
{
var stream =
"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJJU1MiLCJzY29wZSI6Imh0dHBzOi8vbGFyaW0uZG5zY2UuZG91YW5lL2NpZWxzZXJ2aWNlL3dzIiwiYXVkIjoiaHR0cHM6Ly9kb3VhbmUuZmluYW5jZXMuZ291di5mci9vYXV0aDIvdjEiLCJpYXQiOiJcL0RhdGUoMTQ2ODM2MjU5Mzc4NClcLyJ9";
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream);
}
This is the error :
The string needs to be in compact JSON format, which is of the form: Base64UrlEncodedHeader.Base64UrlEndcodedPayload.OPTIONAL,Base64UrlEncodedSignature'.
If you copy the stream in jwt.io website, it works fine :)
I found the solution, I just forgot to Cast the result:
var stream = "[encoded jwt]";
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream);
var tokenS = jsonToken as JwtSecurityToken;
Or, without the cast:
var token = "[encoded jwt]";
var handler = new JwtSecurityTokenHandler();
var jwtSecurityToken = handler.ReadJwtToken(token);
I can get Claims using:
var jti = tokenS.Claims.First(claim => claim.Type == "jti").Value;
new JwtSecurityTokenHandler().ReadToken("") will return a SecurityToken
new JwtSecurityTokenHandler().ReadJwtToken("") will return a JwtSecurityToken
If you just change the method you are using you can avoid the cast in the above answer
You need the secret string which was used to generate encrypt token.
This code works for me:
protected string GetName(string token)
{
string secret = "this is a string used for encrypt and decrypt token";
var key = Encoding.ASCII.GetBytes(secret);
var handler = new JwtSecurityTokenHandler();
var validations = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
var claims = handler.ValidateToken(token, validations, out var tokenSecure);
return claims.Identity.Name;
}
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Email, model.UserName),
new Claim(JwtRegisteredClaimNames.NameId, model.Id.ToString()),
};
var token = new JwtSecurityToken(_config["Jwt:Issuer"],
_config["Jwt:Issuer"],
claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
Then extract content
var handler = new JwtSecurityTokenHandler();
string authHeader = Request.Headers["Authorization"];
authHeader = authHeader.Replace("Bearer ", "");
var jsonToken = handler.ReadToken(authHeader);
var tokenS = handler.ReadToken(authHeader) as JwtSecurityToken;
var id = tokenS.Claims.First(claim => claim.Type == "nameid").Value;
Using .net core jwt packages, the Claims are available:
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "Bearer")]
public class AbstractController: ControllerBase
{
protected string UserId()
{
var principal = HttpContext.User;
if (principal?.Claims != null)
{
foreach (var claim in principal.Claims)
{
log.Debug($"CLAIM TYPE: {claim.Type}; CLAIM VALUE: {claim.Value}");
}
}
return principal?.Claims?.SingleOrDefault(p => p.Type == "username")?.Value;
}
}
I write this solution and it's work for me
protected Dictionary<string, string> GetTokenInfo(string token)
{
var TokenInfo = new Dictionary<string, string>();
var handler = new JwtSecurityTokenHandler();
var jwtSecurityToken = handler.ReadJwtToken(token);
var claims = jwtSecurityToken.Claims.ToList();
foreach (var claim in claims)
{
TokenInfo.Add(claim.Type, claim.Value);
}
return TokenInfo;
}
Extending on cooxkie answer, and dpix answer, when you are reading a jwt token (such as an access_token received from AD FS), you can merge the claims in the jwt token with the claims from "context.AuthenticationTicket.Identity" that might not have the same set of claims as the jwt token.
To Illustrate, in an Authentication Code flow using OpenID Connect,after a user is authenticated, you can handle the event SecurityTokenValidated which provides you with an authentication context, then you can use it to read the access_token as a jwt token, then you can "merge" tokens that are in the access_token with the standard list of claims received as part of the user identity:
private Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage,OpenIdConnectAuthenticationOptions> context)
{
//get the current user identity
ClaimsIdentity claimsIdentity = (ClaimsIdentity)context.AuthenticationTicket.Identity;
/*read access token from the current context*/
string access_token = context.ProtocolMessage.AccessToken;
JwtSecurityTokenHandler hand = new JwtSecurityTokenHandler();
//read the token as recommended by Coxkie and dpix
var tokenS = hand.ReadJwtToken(access_token);
//here, you read the claims from the access token which might have
//additional claims needed by your application
foreach (var claim in tokenS.Claims)
{
if (!claimsIdentity.HasClaim(claim.Type, claim.Value))
claimsIdentity.AddClaim(claim);
}
return Task.FromResult(0);
}
Use this:
public static string Get_Payload_JWTToken(string token)
{
var handler = new JwtSecurityTokenHandler();
var DecodedJWT = handler.ReadJwtToken(token);
string payload = DecodedJWT.EncodedPayload; // Gives Payload
return Encoding.UTF8.GetString(FromBase64Url(payload));
}
static byte[] FromBase64Url(string base64Url)
{
string padded = base64Url.Length % 4 == 0
? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
string base64 = padded.Replace("_", "/").Replace("-", "+");
return Convert.FromBase64String(base64);
}
Though this answer is not answering the original question but its a really very useful feature for C# developers, so adding it as the answer.
Visual Studio 2022 has added a feature to decode the value of a token at runtime.
You can check the feature in Visual Studio 2022 preview (version 17.5.0 preview 2.0)
Mouse over the variable containing the JWT and then select the string manipulation as JWT Decode, and you can see the token value.
I upgraded my WebAPI and Blazor Server side projects from NET5 to NET6 and now I cannot validate my JWT Token. It gets stored with double quotes in local storage
** My JWTHandler Class used to create token **
public class JwtHandler
{
private readonly IConfiguration _configuration;
private readonly IConfigurationSection _jwtSettings;
private readonly IConfigurationSection _googleSettings;
private readonly UserManager<ApplicationUser> _userManager;
public JwtHandler(IConfiguration configuration, UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
_configuration = configuration;
_jwtSettings = _configuration.GetSection("JWT");
_googleSettings = _configuration.GetSection("Google");
}
private SigningCredentials GetSigningCredentials()
{
var key = Encoding.ASCII.GetBytes(_jwtSettings.GetSection("Secret").Value);
var secret = new SymmetricSecurityKey(key);
return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256Signature);
}
private async Task<List<Claim>> GetClaims(ApplicationUser user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
var roles = await _userManager.GetRolesAsync(user);
foreach (var role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
return claims;
}
private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List<Claim> claims)
{
var tokenOptions = new JwtSecurityToken(
issuer: _jwtSettings.GetSection("ValidIssuer").Value,
audience: _jwtSettings.GetSection("ValidAudience").Value,
claims: claims,
expires: DateTime.Now.AddMinutes(Convert.ToDouble(_jwtSettings.GetSection("ExpiryInMinutes").Value)),
signingCredentials: signingCredentials);
return tokenOptions;
}
public async Task<string> GenerateToken(ApplicationUser user)
{
var signingCredentials = GetSigningCredentials();
var claims = await GetClaims(user);
var tokenOptions = GenerateTokenOptions(signingCredentials, claims);
var token = new JwtSecurityTokenHandler().WriteToken(tokenOptions);
return token;
}
public async Task<GoogleJsonWebSignature.Payload> VerifyGoogleToken(ExternalAuthDto externalAuth)
{
try
{
var settings = new GoogleJsonWebSignature.ValidationSettings()
{
Audience = new List<string>() { _googleSettings.GetSection("ClientId").Value }
};
var payload = await GoogleJsonWebSignature.ValidateAsync(externalAuth.IdToken, settings);
return payload;
}
catch (Exception)
{
throw;
}
}
}
** My Code used to store to local storage **
_interceptor.MonitorEvent();
var response = await client.PostAsJsonAsync("Authenticate/login", loginModel);
var result = await response.Content.ReadFromJsonAsync<AuthenticatedModel>();
if (response.IsSuccessStatusCode)
{
var token = result.token;
await _locStorage.SetItemAsync("AuthToken", token);
((AuthStateProvider)_authStateProvider).NotifyUserAuthentication(token);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
showAuthenticationError = false;
loginIsSuccessful = true;
this.NavToPage();
}
** The code that returns an invalid token exception **
var token = await _locStorage.GetItemAsStringAsync("AuthToken");
var client = _clientFactory.CreateClient("meta");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
_interceptor.MonitorEvent();
user = await client.GetFromJsonAsync<UserModel>("User/DashDetails");
var tempDashs = (ICollection<DashboardsDTO>)await client.GetFromJsonAsync<IEnumerable<DashboardsDTO>>("User/Dashboards");
The code above was working just fine before I upgraded from NET5 to NET6
I don't think the solution I have used is the best, if a way to prevent the adding of the double quotes is found please advise.
My solution, : I changed the AuthenticatedHeaderValue token as follows in the code that returns an invalid token exception
From: client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
To: client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Trim('"'));
I am developing a game using Monogame and I want to access my Api so that I can make a login but it always returns me an exception. If I use port 80 I get the following one No connection could be made because the target machine actively refused it and if I use port 5000 I get a 401: Not authorized .
By printing in the console I could come to the conclusion that my try is interrupted at the line response = await client.GetStringAsync(builder.Uri.AbsoluteUri);
Is there something wrong with my code?
Communication class
public class Communication
{
private readonly HttpClient client = new HttpClient();
private const string Uri = "http://localhost:5000/";
private const int Port = 5000;
public Communication()
{
}
public async Task<User> Login(string username, string password)
{
string response;
User user = null;
try
{
var builder = new UriBuilder(Uri + "/Api/Account/Login/")
{
Port = Port
};
builder.Query = $"Username={username}&Password={password}";
Debug.WriteLine("Chegou Aqui!!!!")
response = await client.GetStringAsync(builder.Uri.AbsoluteUri);
if (response == "OK")
{
user = JsonConvert.DeserializeObject<User>(response);
}
}
catch (Exception ex)
{
Debug.WriteLine("\tERROR {0}", ex.Message);
}
return user;
}
}
My Api Login Method
[AllowAnonymous]
[HttpPost("Login")]
public IActionResult Authenticate([FromBody]AuthenticateModel userModel)
{
var user = _userService.Authenticate(userModel.Username, userModel.Password);
if(user == null)
{
return BadRequest(new { message = "Username or Password invalid" });
}
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return Ok(new
{
Id = user.Id,
UserName = user.Username,
Token = tokenString
}) ;
}
This article possibly can help you
You can check your firewall settings or if any antivirus installed in your system, make sure to check the settings of it.
You get error 401: Not authorized because HTTP requests by default configured on port 80, not any other ports.
If the problem persists, check your router or switch configuration, if any is in your route to server.
I have my below code which output the master branch stats in JSON format from Azure DevOps repository and I am capturing the required output. This works when I use the personal access token the authentication works and gets back with the results from the API.
But when I try to generate Access token using the registered app in AAD(has delegated user impersonation enabled for Azure DevOps under API permissions), I am able to generate the access token and then passing it while calling the API, but it returns back with
StatusCode: 203, ReasonPhrase: 'Non-Authoritative Information', Version: 1.1, Content: System.Net.Http.StreamContent
public static async Task GetBuilds()
{
string url = "Azure Dev-Ops API";
var personalaccesstoken = "personalaccesscode";
//var personalaccesstoken = token.GetYourTokenWithClientCredentialsFlow().Result;
string value = null;
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalaccesstoken))));
using (HttpResponseMessage response = await client.GetAsync(url))
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
dynamic jsonObject = JsonConvert.DeserializeObject(responseBody);
value = jsonObject;
}
}
if (value != null)
{
Console.WriteLine(value);
}
}
public static async Task<string> GetYourTokenWithClientCredentialsFlow()
{
string tokenUrl = $"https://login.microsoftonline.com/{tenant ID}/oauth2/token";
var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenUrl);
tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = "client ID",
["client_secret"] = "client secret",
["resource"] = "https://graph.microsoft.com/"
});
dynamic json;
dynamic token;
string accessToken;
HttpClient client = new HttpClient();
var tokenResponse = client.SendAsync(tokenRequest).Result;
json = await tokenResponse.Content.ReadAsStringAsync();
token = JsonConvert.DeserializeObject(json);
accessToken = token.access_token;
return accessToken;
}
Tried to test using postman using the access token generated using above code and get as below screenshot.
what I am doing wrong here and how can I fix the problem?
The azure ad access token is a bearer token. You do not need to use it as basic auth.
Try with the following code:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", GetYourTokenWithClientCredentialsFlow().Result);
Update:
Register a new app
Set the app as a public client by default
Add permission to DevOps API
Create a new project, install Microsoft.IdentityModel.Clients.ActiveDirectory package
Code sample
class Program
{
static string azureDevOpsOrganizationUrl = "https://dev.azure.com/jack0503/"; //change to the URL of your Azure DevOps account; NOTE: This must use HTTPS
static string clientId = "0a1f****-****-****-****-a2a4****7f69"; //change to your app registration's Application ID
static string replyUri = "https://localhost/"; //change to your app registration's reply URI
static string azureDevOpsResourceId = "499b84ac-1321-427f-aa17-267ca6975798"; //Constant value to target Azure DevOps. Do not change
static string tenant = "hanxia.onmicrosoft.com"; //your tenant ID or Name
static String GetTokenInteractively()
{
AuthenticationContext ctx = new AuthenticationContext("https://login.microsoftonline.com/" + tenant); ;
IPlatformParameters promptBehavior = new PlatformParameters(PromptBehavior.Auto | PromptBehavior.SelectAccount);
AuthenticationResult result = ctx.AcquireTokenAsync(azureDevOpsResourceId, clientId, new Uri(replyUri), promptBehavior).Result;
return result.AccessToken;
}
static String GetToken()
{
AuthenticationContext ctx = new AuthenticationContext("https://login.microsoftonline.com/" + tenant); ;
UserPasswordCredential upc = new UserPasswordCredential("jack#hanxia.onmicrosoft.com", "yourpassword");
AuthenticationResult result = ctx.AcquireTokenAsync(azureDevOpsResourceId, clientId, upc).Result;
return result.AccessToken;
}
static void Main(string[] args)
{
//string token = GetTokenInteractively();
string token = GetToken();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(azureDevOpsOrganizationUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = client.GetAsync("_apis/projects").Result;
if (response.IsSuccessStatusCode)
{
Console.WriteLine("\tSuccesful REST call");
var result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
}
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
throw new UnauthorizedAccessException();
}
else
{
Console.WriteLine("{0}:{1}", response.StatusCode, response.ReasonPhrase);
}
Console.ReadLine();
}
}
}
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/securetoken#system.gserviceaccount.com");
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/securetoken#system.gserviceaccount.com 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
}
I'm sure by now you have figured out the solution for this, but for future people who come across this question.
Set the KeyId for the X509SecurityKey
x509Data.Select(cert => new X509SecurityKey(new X509Certificate2(Encoding.UTF8.GetBytes(cert.Value)))
{
KeyId = cert.Key
})
.ToArray()
This will allow the TokenValidationParameters to look up which issuerKey to validate against.