< Summary - Kestrun — Combined Coverage

Information
Class: Kestrun.Jwt.JwkUtilities
Assembly: Kestrun
File(s): /home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Jwt/JwkUtilities.cs
Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff
Line coverage
100%
Covered lines: 19
Uncovered lines: 0
Coverable lines: 19
Total lines: 65
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 11/19/2025 - 02:25:56 Line coverage: 100% (19/19) Branch coverage: 100% (6/6) Total lines: 65 Tag: Kestrun/Kestrun@98ff905e5605a920343154665980a71211a03c6d 11/19/2025 - 02:25:56 Line coverage: 100% (19/19) Branch coverage: 100% (6/6) Total lines: 65 Tag: Kestrun/Kestrun@98ff905e5605a920343154665980a71211a03c6d

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ComputeThumbprintRsa(...)100%44100%
ComputeThumbprintFromCertificate(...)100%22100%
Base64UrlEncode(...)100%11100%

File(s)

/home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Jwt/JwkUtilities.cs

#LineLine coverage
 1using System.Security.Cryptography;
 2using System.Security.Cryptography.X509Certificates;
 3using System.Text;
 4
 5namespace Kestrun.Jwt;
 6
 7/// <summary>
 8/// Utilities for working with JSON Web Keys (JWK), including RFC 7638 thumbprints.
 9/// </summary>
 10public static class JwkUtilities
 11{
 12    /// <summary>
 13    /// Computes the RFC 7638 JWK thumbprint for an RSA public key given its Base64Url-encoded parameters.
 14    /// </summary>
 15    /// <param name="nBase64Url">The Base64Url-encoded RSA modulus (n).</param>
 16    /// <param name="eBase64Url">The Base64Url-encoded RSA public exponent (e).</param>
 17    /// <returns>The Base64Url-encoded SHA-256 hash of the canonical JWK representation.</returns>
 18    public static string ComputeThumbprintRsa(string nBase64Url, string eBase64Url)
 19    {
 1620        if (string.IsNullOrWhiteSpace(nBase64Url))
 21        {
 322            throw new ArgumentException("Value cannot be null or empty.", nameof(nBase64Url));
 23        }
 24
 1325        if (string.IsNullOrWhiteSpace(eBase64Url))
 26        {
 327            throw new ArgumentException("Value cannot be null or empty.", nameof(eBase64Url));
 28        }
 29
 30        // Canonical JWK member order per RFC 7638 for RSA: e, kty, n
 1031        var canonicalJwk = "{\"e\":\"" + eBase64Url + "\",\"kty\":\"RSA\",\"n\":\"" + nBase64Url + "\"}";
 1032        var bytes = Encoding.UTF8.GetBytes(canonicalJwk);
 1033        var hash = SHA256.HashData(bytes);
 1034        return Base64UrlEncode(hash);
 35    }
 36
 37    /// <summary>
 38    /// Computes the RFC 7638 JWK thumbprint for an RSA public key extracted from a certificate.
 39    /// </summary>
 40    /// <param name="certificate">The X.509 certificate containing the RSA public key.</param>
 41    /// <returns>The Base64Url-encoded SHA-256 hash of the canonical JWK representation.</returns>
 42    public static string ComputeThumbprintFromCertificate(X509Certificate2 certificate)
 43    {
 444        ArgumentNullException.ThrowIfNull(certificate);
 45
 346        using var rsa = certificate.GetRSAPublicKey() ?? throw new NotSupportedException("Certificate does not contain a
 247        var parameters = rsa.ExportParameters(false);
 248        var n = Base64UrlEncode(parameters.Modulus);
 249        var e = Base64UrlEncode(parameters.Exponent);
 250        return ComputeThumbprintRsa(n, e);
 251    }
 52
 53    /// <summary>
 54    /// Encodes data using Base64Url encoding as specified in RFC 7515.
 55    /// </summary>
 56    /// <param name="data">The data to encode.</param>
 57    /// <returns>The Base64Url-encoded string.</returns>
 58    private static string Base64UrlEncode(ReadOnlySpan<byte> data)
 59    {
 1460        return Convert.ToBase64String(data)
 1461            .TrimEnd('=')
 1462            .Replace('+', '-')
 1463            .Replace('/', '_');
 64    }
 65}