Bounded source-bound public keys, freshness and directory proof status.
revision is SHA-256 over the fetched JSON bytes, not an origin-assigned sequence.
Default IDs are computed RFC thumbprints; directory-assigned IDs never replace
cryptographic identity or thumbprint revocation. Key restrictions remain
enforced by RequestSeal.PublicKey. The cache's :clock supports
caller-controlled time for resolution and fetching. etag is the source's
ETag validator, if it sent one; the cache revalidates conditionally with it.
Summary
Functions
Find a fresh, nonrevoked key by its source-selected ID under an algorithm allowlist.
Types
@type t() :: %RequestSeal.Discovery.KeySet{ etag: binary() | nil, expires_at: integer(), fetched_at: integer(), keys: %{required(binary()) => RequestSeal.Discovery.Resolution.t()}, origin: binary(), proof: :signed | :unsigned | :not_applicable, revision: binary(), source: RequestSeal.Discovery.Source.t() }
Functions
@spec lookup(t(), binary(), [RequestSeal.Crypto.algorithm()]) :: {:ok, RequestSeal.Discovery.Resolution.t()} | :error
Find a fresh, nonrevoked key by its source-selected ID under an algorithm allowlist.
Lookup uses system time. It revalidates the set's source, recomputes the key's thumbprint, and rejects stale, revoked, incompatible or malformed entries.
Parameters
set- aRequestSeal.Discovery.KeySet, normally fromRequestSeal.Discovery.fetch/2.keyid- an ID under the source'skey_idmode: an RFC 7638 thumbprint (43 base64url characters) by default, or a directory-assigned ID of 1–256 printable ASCII bytes withkey_id: :directory.algorithms- 1 to 64 algorithm identifiers accepted by a policy (the names inRequestSeal.Crypto.algorithms/0or{:jws, name}tuples). The first entry the key can use, and that matches any algorithm the source asserted, is selected.
Returns
{:ok, %RequestSeal.Discovery.Resolution{}}- the entry withalgorithmset to the selected algorithm andrevisionset to the set's revision.:error- the ID is malformed for the mode or absent; the set or entry has expired; the thumbprint is revoked by the source; no allowed algorithm fits the key; the source or allowlist is invalid; orsetis not a key set.
Examples
A key set normally comes from RequestSeal.Discovery.fetch/2; this example
builds one from a locally generated Ed25519 key so it runs offline.
iex> {public, _private} = :crypto.generate_key(:eddsa, :ed25519)
iex> {:ok, key} =
...> RequestSeal.PublicKey.import(
...> %{"kty" => "OKP", "crv" => "Ed25519", "x" => Base.url_encode64(public, padding: false)},
...> :jwk
...> )
iex> {:ok, thumbprint} = RequestSeal.PublicKey.thumbprint(key)
iex> {:ok, source} =
...> RequestSeal.Discovery.Source.new(%{type: :jwks_uri, location: "https://keys.example/jwks.json"})
iex> entry = %RequestSeal.Discovery.Resolution{
...> key: key,
...> key_id: thumbprint,
...> thumbprint: thumbprint,
...> algorithm: "ed25519",
...> origin: "https://keys.example",
...> source_type: :jwks_uri,
...> location: source.location,
...> fetched_at: 0,
...> expires_at: 253_402_300_799,
...> proof: :not_applicable
...> }
iex> set = %RequestSeal.Discovery.KeySet{
...> source: source,
...> origin: "https://keys.example",
...> keys: %{thumbprint => entry},
...> fetched_at: 0,
...> expires_at: 253_402_300_799,
...> revision: "example-revision",
...> proof: :not_applicable
...> }
iex> {:ok, resolution} =
...> RequestSeal.Discovery.KeySet.lookup(set, thumbprint, ["ecdsa-p256-sha256", "ed25519"])
iex> {resolution.algorithm, resolution.revision, resolution.thumbprint == thumbprint}
{"ed25519", "example-revision", true}
iex> RequestSeal.Discovery.KeySet.lookup(set, thumbprint, ["ecdsa-p256-sha256"])
:error
iex> RequestSeal.Discovery.KeySet.lookup(set, "unknown", ["ed25519"])
:error