# jwk/thumbprint ## Purpose Compute the JWK Thumbprint of an RSA public key per RFC 7638 §3.2. The thumbprint is a deterministic hash over the canonical JSON form of the public-key members (`e`, `kty`, `n` in alphabetical order with no whitespace), giving every RSA key a stable identifier independent of its wire format. Used downstream for `kid` derivation, key rotation diffing, and key-pinning protocols. ## Features - RFC 7638 §3.2 conformant — RSA member ordering `e`, `kty`, `n` - Default SHA-256 hash; SHA-1 / SHA-384 / SHA-512 supported via `hash` option - Accepts both canonical `RsaPublicKey` and `RsaJwk` shapes - Hand-built canonical JSON byte string (does NOT use `JSON.stringify` — member order is implementation-defined for that API) - Worked-example matched against the RFC 7638 §3.1 reference value `"NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"` - `jwkThumbprintBase64Url` convenience returns the URL-safe base64 encoding directly - All thrown errors are `CryptoRsaError` with `INVALID_KEY` / `UNSUPPORTED_HASH` ## Usage: Basic Example ```ts import { jwkThumbprint } from "@suaveplan/crypto-rsa/jwk"; const fingerprint = jwkThumbprint(publicKey); // 32 bytes (SHA-256 default) ``` ## Usage: Advanced Example The `kid` JWK member is conventionally set to the base64url-encoded SHA-256 thumbprint. Combine `jwkThumbprintBase64Url` with `serializeRsaPublicKeyJwk` to populate it on emit: ```ts import { jwkThumbprintBase64Url, serializeRsaPublicKeyJwk, } from "@suaveplan/crypto-rsa"; const baseJwk = serializeRsaPublicKeyJwk(publicKey); const jwkWithKid = { ...baseJwk, kid: jwkThumbprintBase64Url(publicKey), }; ``` ## API Reference ### `jwkThumbprint(key, options?)` - `key: RsaPublicKey | RsaJwk` — public key or JWK - `options.hash?: RsaHashAlgorithm` — defaults to `"SHA-256"` - **returns** `Uint8Array` — digest bytes - **throws** `CryptoRsaError(CRYPTO_RSA.UNSUPPORTED_HASH)` on bad hash; `CRYPTO_RSA.INVALID_KEY` on missing `e` or `n` ### `jwkThumbprintBase64Url(key, options?)` Convenience: returns `toBase64Url(jwkThumbprint(key, options))`. ### `JwkThumbprintOptions` - `hash?: RsaHashAlgorithm` ## Implementation Notes - The canonical JSON byte string is `'{"e":"","kty":"RSA","n":""}'`. Members are alphabetically ordered per RFC 7638 §3.2; only the three required members participate in the digest. - `JSON.stringify` is NOT used because member-order in object iteration is implementation-defined for non-integer keys; constructing the byte string by hand is the only correctness-stable approach. - When the input is a `RsaPublicKey` (canonical bigint form), the implementation routes through `serializeRsaPublicKeyJwk` to obtain the base64url members, then concatenates the canonical JSON shape. - Hash algorithm validation runs BEFORE member-validity checks so consumers see `UNSUPPORTED_HASH` on bad hashes regardless of key validity — useful for fail-fast configuration validators.