Skip to content

Instantly share code, notes, and snippets.

@infamousjoeg
Forked from rbrayb/Helper.cs
Created January 31, 2022 19:17
Show Gist options
  • Save infamousjoeg/7d94337b898763231aa16f1044681806 to your computer and use it in GitHub Desktop.
Save infamousjoeg/7d94337b898763231aa16f1044681806 to your computer and use it in GitHub Desktop.
Validating an ADFS JWT token
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ValidateJWTConsoleApp
{
class Helper
{
internal static class AsyncHelper
{
private static readonly TaskFactory TaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
public static void RunSync(Func<Task> func)
{
TaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
}
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return TaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
}
}
}
}
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Threading;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using static ValidateJWTConsoleApp.Helper;
// Derived from https://www.jerriepelser.com/blog/manually-validating-rs256-jwt-dotnet/
namespace ValidateJWTConsoleApp
{
class Program
{
static void Main(string[] args)
{
// ADFS FQDN
const string ADFSDomain = "https://my-adfs/adfs/";
// Identifier
const string ADFSAudience = "https://localhost:44326/";
const string testToken = "eyJ...6-1A";
try
{
// Download the OIDC configuration which contains the JWKS
// NB!!: Downloading this takes time, so do not do it very time you need to validate a token, Try and do it only once in the lifetime of your application!!
IConfigurationManager<OpenIdConnectConfiguration> configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>($"{ADFSDomain}.well-known/openid-configuration",
new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration openIdConfig = AsyncHelper.RunSync(async () => await configurationManager.GetConfigurationAsync(CancellationToken.None));
// Configure the TokenValidationParameters. Assign the SigningKeys which were downloaded from ADFS.
// Also set the Issuer and Audience(s) to validate.
// Note: You need to set the ADFS domain as above so that the program can find the /adfs/.well-known/openid-configuration endpoint.
// However, this is not the issuer in the token so you need to add the /adfs/services/trust endpoint as below.
// If this is not configured corrrectly, you get the exception:
// Message=IDX10205: Issuer validation failed. Issuer: 'http://my-adfs/adfs/services/trust'.
// Did not match: validationParameters.ValidIssuer: 'https://my-adfs/adfs/' or validationParameters.ValidIssuers: 'null'.
TokenValidationParameters validationParameters =
new TokenValidationParameters
{
ValidIssuer = ADFSDomain,
ValidIssuers = new[] { ADFSDomain, "http://my-adfs/adfs/services/trust" },
ValidAudiences = new[] { ADFSAudience },
IssuerSigningKeys = openIdConfig.SigningKeys
};
// Now validate the token. If the token is not valid for any reason, an exception will be thrown by the method
SecurityToken validatedToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var user = handler.ValidateToken(testToken, validationParameters, out validatedToken);
// The ValidateToken method above will return a ClaimsPrincipal. Get the claims form user.Claims.
// These are OAuth claims e.g. "aud", "iss" etc.
Console.WriteLine("Token is validated" + "\n");
foreach (var Claim in user.Claims)
{
Console.WriteLine("Claim is " + Claim);
}
}
catch (Exception e)
{
Console.WriteLine($"Error occurred while validating token: {e.Message}");
}
Console.WriteLine();
Console.WriteLine("Press ENTER to continue...");
Console.ReadLine();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment