azure-activedirectory-identitymodel-extensions-for-dotnet icon indicating copy to clipboard operation
azure-activedirectory-identitymodel-extensions-for-dotnet copied to clipboard

[Feature Request] Changing the kid header for a JWT

Open drmathias opened this issue 3 years ago • 7 comments

Is your feature request related to a problem? Please describe. When using Azure Key Vault to sign a token, the kid value in the header is set with the key identifier for the Azure Key Vault key. Any tokens that are signed therefore expose the location of the keys/secrets, and for the kid header value to be unique, it forces us to point to a specific version of the key rather than relying on the latest.

var azureServiceTokenProvider = new AzureServiceTokenProvider();
var callback = new KeyVaultSecurityKey.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback);

var certificateKeyId = "https://my-key-vault-instance.vault.azure.net/keys/certificate-name";
var tokenHandler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(),
    Issuer = _apiOptions.Value.Authority,
    Expires = DateTime.UtcNow.AddHours(24),
    IssuedAt = DateTime.UtcNow,
    SigningCredentials = new SigningCredentials(new KeyVaultSecurityKey(certificateKeyId, callback), SecurityAlgorithms.RsaSha256)
    {
        CryptoProviderFactory = new CryptoProviderFactory { CustomCryptoProvider = new KeyVaultCryptoProvider() }
    }
};

var jwt = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(jwt);
{
  "alg": "RS256",
  "kid": "https://my-key-vault-instance.vault.azure.net/keys/certificate-name",
  "typ": "JWT"
}

Describe the solution you'd like The kid value would be set to either the certificate thumbprint or the version string when creating a new token.

Describe alternatives you've considered Being able to set the kid value in the token descriptor would be a workable alternative.

var tokenDescriptor = new SecurityTokenDescriptor
{
    AdditionalHeaderClaims = new Dictionary<string, object>
    {
        { "kid", customKidHeaderValue }
    }
}
var tokenDescriptor = new SecurityTokenDescriptor
{
    KeyId = customKidHeaderValue
}

As of now, I've been able to create workaround using reflection. This is done by creating a new type and overriding the KeyId property of KeyVaultSecurityKey, returning a different value if the calling type is JwtHeader.

drmathias avatar Mar 25 '22 11:03 drmathias

@drmathias you bring up a good point, if you could specify easily the 'kid' to use, would that work?

brentschmaltz avatar Mar 31 '22 16:03 brentschmaltz

Yes, that solution seems alright

drmathias avatar Mar 31 '22 19:03 drmathias

Is there any suggested workaround for this? Other than reflection or creating our own implementation of KeyVaultSecurityKey

logiclabs avatar Mar 07 '24 16:03 logiclabs