# `Attesto.SdJwtVc`
[🔗](https://github.com/XukuLLC/attesto/blob/v2.0.1/lib/attesto/sd_jwt_vc.ex#L1)

SD-JWT-based Verifiable Credentials (SD-JWT VC), draft-ietf-oauth-sd-jwt-vc.

The IETF profile of `Attesto.SdJwt` used by the EUDI wallet stack (and its
High-Assurance Interoperability Profile, HAIP): an SD-JWT whose Issuer-signed
JWT carries a credential *type* (`vct`), an issuer (`iss`), an optional holder
key binding (`cnf`), an optional Token Status List reference (`status`), and
the usual temporal claims, typed `vc+sd-jwt` or `dc+sd-jwt` in the JOSE `typ`
header.

This module adds the VC-specific claim rules on top of the base SD-JWT
mechanism; the selective-disclosure machinery, recursive verification, and Key
Binding JWT handling all come from `Attesto.SdJwt`.

  * `issue/2` — assemble and sign an SD-JWT VC: sets `iss`/`vct`/`iat` (and
    optional `exp`/`nbf`/`cnf`/`status`/`sub`), makes the chosen credential
    claims selectively disclosable, and stamps the JOSE `typ` from the optional
    `:typ` (`vc+sd-jwt` or `dc+sd-jwt`; defaults to `vc+sd-jwt`).
  * `verify/3` — verify the issuer signature (typed `vc+sd-jwt`), reconstruct
    the disclosed claims, and enforce the VC claim rules: `iss` and `vct`
    REQUIRED and non-empty, `exp` (if present) not passed, `nbf` (if present)
    reached. Holder binding is a separate step - pass the returned `cnf` key to
    `Attesto.SdJwt.verify_key_binding/3` with the presentation's nonce/audience.

Conn-free and fail-closed, like the rest of attesto core.

# `verified`

```elixir
@type verified() :: %{
  claims: map(),
  vct: String.t(),
  iss: String.t(),
  cnf: map() | nil,
  key_binding_jwt: String.t() | nil,
  issuer_jwt: String.t(),
  disclosures: [String.t()]
}
```

# `verify_error`

```elixir
@type verify_error() ::
  Attesto.SdJwt.verify_error()
  | :missing_iss
  | :missing_vct
  | :expired
  | :not_yet_valid
```

# `issue`

```elixir
@spec issue(keyword(), keyword()) :: String.t()
```

Issue an SD-JWT VC.

Required options:

  * `:iss` - the issuer identifier (its `.well-known/jwt-vc-issuer` or DID).
  * `:vct` - the verifiable credential type (a collision-resistant string/URI).
  * `:pem` - the issuer signing key (PEM).

Optional:

  * `:claims` - the credential subject claims (a map). Defaults to `%{}`.
  * `:disclosable` - which of those claim names to make selectively
    disclosable. Defaults to all of `:claims`. Registered claims
    (`iss`/`vct`/`cnf`/`status`/`iat`/`exp`/`nbf`/`sub`) are never made
    disclosable even if listed here - they always remain visible, so a
    holder cannot strip holder-binding (`cnf`) or a status reference.
  * `:cnf` - the holder key-binding confirmation (RFC 7800), e.g.
    `%{"jwk" => holder_public_jwk}`. Included for later Key Binding.
  * `:status` - a Token Status List reference map, typically built with
    `Attesto.StatusList.reference/2`. Always visible when present.
  * `:iat` / `:exp` / `:nbf` / `:sub` - standard claims (unix seconds / string).
  * `:now` - clock reference for a defaulted `:iat`.
  * `:kid` - JOSE `kid` header. `:sd_alg` - SD hashing algorithm.
  * `:typ` - the SD-JWT VC media type stamped in the JOSE `typ` header,
    `"vc+sd-jwt"` or `"dc+sd-jwt"` (the credential configuration's `format`).
    Defaults to `"vc+sd-jwt"`.
  * `:x5c` - the issuer X.509 certificate chain (RFC 7515 §4.1.6): a non-empty
    list of base64 DER certificate strings, stamped in the JOSE `x5c` header so
    a verifier can bind the credential to a trusted issuer certificate (HAIP).
    Omitted when nil.

Returns the SD-JWT VC Issuance string (no Key Binding JWT).

# `verify`

```elixir
@spec verify(String.t(), map() | [map()] | list(), keyword()) ::
  {:ok, verified()} | {:error, verify_error()}
```

Verify an SD-JWT VC presentation and reconstruct the disclosed claims.

`jwks` is the issuer's JWK Set. Options are passed through to
`Attesto.SdJwt.verify/3` (e.g. `:accepted_algs`), plus:

  * `:now` / `:max_age_seconds` - clock reference for the temporal checks.

Returns `{:ok, %{claims:, vct:, iss:, cnf:, key_binding_jwt:, ...}}`. Holder
binding is NOT checked here - if `cnf` is present and the presentation carries
a Key Binding JWT, pass both to `Attesto.SdJwt.verify_key_binding/3` with the
verifier's expected `nonce`/`audience`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
