Today I was checking if I can migrate my app to .NET 8. At first everything was ok by when I tried to log in, I get following error in the console:
Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10506: Signature validation failed. The user defined 'Delegate' specified on TokenValidationParameters did not return a 'Microsoft.IdentityModel.JsonWebTokens.JsonWebToken', but returned a 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' when validating token
My client is using customized implementation of PingID. Tokens are validated using introspection that why I've written custom token validator:
public class PingTokenValidator : ISecurityTokenValidator
{
private readonly IConfiguration configuration;
private readonly ILogger log;
private readonly OpenIdConnectConfiguration openIdConnectConfiguration;
private readonly JwtSecurityTokenHandler tokenHandler;
public PingTokenValidator(OpenIdConnectConfiguration openIdConnectConfiguration,
IConfiguration configuration)
{
this.tokenHandler = new();
this.openIdConnectConfiguration = openIdConnectConfiguration;
this.configuration = configuration;
this.log = Log.ForContext<PingTokenValidator>();
}
public bool CanReadToken(string securityToken)
{
return true;
}
public ClaimsPrincipal ValidateToken(string securityToken,
TokenValidationParameters validationParameters,
out SecurityToken validatedToken)
{
try
{
var principal = this.tokenHandler.ValidateToken(securityToken, validationParameters, out validatedToken);
if (tokenExistInCache && cachedToken == securityToken)
{
return principal;
}
if (!this.IsValid(securityToken))
{
throw new SecurityTokenValidationException("Token not authorised by PingID.");
}
return principal;
}
catch (Exception e)
{
this.log.Error(e, "Error validating JWT token");
throw;
}
}
public bool CanValidateToken { get; }
public int MaximumTokenSizeInBytes { get; set; } = TokenValidationParameters.DefaultMaximumTokenSizeInBytes;
private bool IsValid(string securityToken)
{
var options = new RestClientOptions
{
Authenticator = new HttpBasicAuthenticator(this.configuration["FDID:UserId"]!, this.configuration["FDID:Secret"]!)
};
var client = new RestClient(options);
var request = new RestRequest(this.openIdConnectConfiguration.IntrospectionEndpoint, Method.Post);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "urn:pingidentity.com:oauth2:grant_type:validate_bearer");
request.AddParameter("token", securityToken);
var response = client.Execute(request);
if (!response.IsSuccessful)
{
this.log.Error(response.ErrorException, "Error validating JWT token. Response message: {@TokenIntrospectionMessage}", response.Content);
return false;
}
if (string.IsNullOrWhiteSpace(response.Content))
{
this.log.Error("Ping returned empty response: {@IntrospectionResponse}", response);
return false;
}
var tokenSummary = JsonSerializer.Deserialize<PingTokenSummary>(response.Content, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return tokenSummary is
{
Active: true
};
}
}
I was looking for other interfaces that could be used instead of ISecurityTokenValidator
but with no luck. Am I missing something?
authenticationBuilder.AddJwtBearer(options =>
and make sure that SignatureValidator = delegate returns instance ofnew JsonWebToken
and notnew JwtSecurityToken
as was my case. It fixed it for me. – Wept