AttestoClient.WalletAttestation (AttestoClient v2.3.1)

Copy Markdown View Source

Build the two JWTs of OAuth 2.0 Attestation-Based Client Authentication (draft-ietf-oauth-attestation-based-client-auth-10), the client-side mirror of Attesto.WalletAttestation.verify/3 and the client-auth method OID4VCI recommends for native-app wallets over private_key_jwt/mTLS.

Two artifacts, signed by two different keys:

  • attestation/2 - the Client Attestation JWT (typ oauth-client-attestation+jwt), issued by the Wallet Provider (Client Attester) and signed by its key. It binds the wallet instance's public key into cnf and names the instance's client_id in sub. It is long-lived and reused across many requests; an :x5c header lets the server chain the signer to a configured trust anchor.

  • pop/2 - the Client Attestation PoP JWT (typ oauth-client-attestation-pop+jwt), minted fresh per request and signed by the instance key (the private half of the attestation's cnf key), proving possession to one aud (the server's identifier).

The client presents them in the OAuth-Client-Attestation and OAuth-Client-Attestation-PoP headers; AttestoClient.OAuthHTTP's {:client_attestation, ...} client-auth attaches both. Signing and key-bound :alg/:kid validation behave as in AttestoClient.Wallet.Proof (shared AttestoClient.Builder internals).

Summary

Functions

Build a Client Attestation JWT, returning {:ok, compact_jws} or {:error, reason}. Fails fast on invalid input.

Build a Client Attestation PoP JWT, returning {:ok, compact_jws} or {:error, reason}. Fails fast on invalid input.

Types

attestation_opt()

@type attestation_opt() ::
  {:client_id, String.t()}
  | {:instance_key, jwk()}
  | {:x5c, [String.t()]}
  | {:lifetime, pos_integer()}
  | {:alg, String.t()}
  | {:kid, String.t()}
  | {:now, integer()}

error()

@type error() ::
  :invalid_key
  | :invalid_client_id
  | :invalid_audience
  | :invalid_instance_key
  | :invalid_lifetime
  | :invalid_jti
  | :unsupported_alg
  | :unsupported_key
  | {:signing_failed, String.t()}

jwk()

@type jwk() :: JOSE.JWK.t() | map()

pop_opt()

@type pop_opt() ::
  {:client_id, String.t()}
  | {:audience, String.t()}
  | {:challenge, String.t()}
  | {:lifetime, pos_integer()}
  | {:jti, String.t()}
  | {:alg, String.t()}
  | {:kid, String.t()}
  | {:now, integer()}

Functions

attestation(provider_key, opts)

@spec attestation(jwk(), [attestation_opt()]) :: {:ok, String.t()} | {:error, error()}

Build a Client Attestation JWT, returning {:ok, compact_jws} or {:error, reason}. Fails fast on invalid input.

provider_key is the Wallet Provider (Client Attester) private key that signs the attestation. Required options:

  • :client_id - the wallet instance's client identifier (becomes sub).
  • :instance_key - the wallet instance's key; its public half is embedded as the cnf confirmation JWK the PoP must be signed by.

Optional: :x5c (a list of base64 DER certificates for the x5c header, so the server can chain the signer to a trust anchor), :lifetime (seconds to exp, default 3600), and :alg, :kid, :now as in AttestoClient.Wallet.Proof.build/2.

pop(instance_key, opts)

@spec pop(jwk(), [pop_opt()]) :: {:ok, String.t()} | {:error, error()}

Build a Client Attestation PoP JWT, returning {:ok, compact_jws} or {:error, reason}. Fails fast on invalid input.

instance_key is the wallet instance private key - the private half of the attestation's cnf key. Required options:

  • :client_id - the wallet instance's client identifier (becomes iss).
  • :audience - the server's identifier the PoP is presented to (aud); an AS issuer URL or a resource identifier, single-valued.

Optional: :challenge (echo a server-issued Challenge), :jti (default a fresh random value), :lifetime (seconds to exp, default 120), and :alg, :kid, :now.