Today,we can use jwtSecurityTokenHandler with System.IdentityModel.Tokens.Jwt.
ATTENTION
System.IdentityModel.Tokens.Jwt version 5.x.x requires .NET Framework 5.x.
If the target framework is .NET Framework 4.5.x or 4.6.x take latest stable 4.x.x version of System.IdentityModel.Tokens.Jwt package.
Validate JWT
public override async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
...
// validate JWT
try
{
await JwtValidator.ValidateJwtToken(token, cancellationToken);
}
catch (SecurityTokenException e)
{
var validationSucceeded = false;
Contract.Assert(validationSucceeded, $"{ErrorCode.UNAUTHORIZED}JWT validation failed ({e.Message}).");
}
...
}
public class JwtValidator
{
private const string STS_DISCOVERY_ENDPOINT_SUFFIX = ".well-known/openid-configuration";
private const string URI_DELIMITER = "/";
public static async Task<SecurityToken> ValidateJwtToken(string token, CancellationToken cancellationToken)
{
var aadInstance = "https://login.microsoftonline.com/{0}";
var tenant = "example.com";
var audience = "853fb202-4201-4e20-97ae-4d5840d9490f";
var authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
// Fetch configuration
var stsDiscoveryEndpoint = string.Concat(authority, URI_DELIMITER, STS_DISCOVERY_ENDPOINT_SUFFIX);
ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint);
var config = await configManager.GetConfigurationAsync(cancellationToken);
// extract issuer and token for validation
var issuer = config.Issuer;
var signingTokens = config.SigningTokens.ToList();
// validate token
var validationParameters = CreateTokenValidationParameters(signingTokens, issuer, audience);
var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
SecurityToken jwt;
jwtSecurityTokenHandler.ValidateToken(token, validationParameters, out jwt);
return jwt;
}
private static TokenValidationParameters CreateTokenValidationParameters(List<SecurityToken> signingTokens, string issuer, string audience)
{
Contract.Requires(null != signingTokens);
Contract.Requires(!string.IsNullOrWhiteSpace(issuer));
return new TokenValidationParameters()
{
ValidAudience = audience,
ValidIssuer = issuer,
IssuerSigningTokens = signingTokens,
CertificateValidator = X509CertificateValidator.None,
ValidateLifetime = true
};
}
}
Also i want to return my own token from validate method.
When using OpenIdConnectConfiguration configManager.GetConfigurationAsync(cancellationToken); has to be called in async context by using await (Implies that the surrounding method has to be async).
Otherwise the method call GetConfigurationAsync(cancellationToken) did never return. Even when I tried to run the asynchronous method synchronously by calling .Result or using other mechanisms to run ansynchronous methods synchronous the method didn’t return.
You can see more details about Manual JWT Validation against Azure Active Directory in this blog.
.NET CoreApp, that's should beIssuerSigningKeys = config.SigningKeys.