โ† all docs

OID4VC High Assurance Interoperability Profile (HAIP) โ€” Conformance Audit

Spec: openid.net/specs/openid4vc-high-assurance-interoperability-profile-sd-jwt-vc-1_0.html
Audited: 2026-05-16
Scope: verifiably-go as orchestrator (not issuer/verifier DPG); walt.id 0.18.2 as primary DPG.


Legend

Symbol Meaning
โœ… Conformant
โš ๏ธ Partial / conditional
โŒ Gap โ€” action required
N/A Not applicable to this component

1. Credential Format

Requirement Status Notes
SD-JWT VC (vc+sd-jwt) MUST be supported โœ… wired via sd_jwt_vc (IETF) in schema catalog
mdoc (mso_mdoc) SHOULD be supported โš ๏ธ format recognized, no revocation support
W3C VCDM 2.0 (ldp_vc) is out of scope for HAIP N/A still supported for non-HAIP flows

2. Issuance (OID4VCI)

Requirement Status Notes
Authorization Code Flow โœ… delegated to walt.id
Pre-authorized Code Flow โœ… used in single / bulk issuance
credential_offer URI via QR โœ… offerURI returned and surfaced to operator
issuer_state binding โœ… handled by walt.id
Proof-of-possession (DPoP / key-binding) โš ๏ธ enforced by walt.id; verifiably-go doesn't inspect proof
Issuer metadata at /.well-known/openid-credential-issuer โš ๏ธ served by walt.id; verifiably-go proxies the offer, not the metadata
credential_identifier in offer โœ… schema-id mapped to credential config
Batch issuance (/batch_credential) โš ๏ธ bulk.go issues N single credentials; no true batch endpoint
Display metadata for credentials โš ๏ธ SchemaName propagated; display array not surfaced

3. Presentation (OID4VP)

Requirement Status Notes
vp_token returned via response_mode=direct_post โœ… verified in internal/adapters/waltid/verifier.go
response_mode=direct_post.jwt (HAIP REQUIRED) โŒ Gap: HAIP mandates JARM-encrypted response; walt.id 0.18.2 supports direct_post only
client_id_scheme=x509_san_dns (HAIP REQUIRED) โŒ Gap: walt.id uses redirect_uri as client_id; x509 cert not provisioned
client_id_scheme=did โœ… current default in walt.id
Presentation exchange (DIF PE) โœ… presentation_definition wired via OID4VP template
nonce freshness โœ… session state enforces one-time use
SD-JWT selective disclosure โœ… disclosed fields extracted and stored in DisclosedFields
vp_token as SD-JWT (not LD-Proof) โœ… verified by regression tests in vp_token_regression_test.go

4. Key Binding & Wallet Attestation

Requirement Status Notes
wallet_attestation JWT in token request โŒ Gap: HAIP ยง6 requires wallets to present a wallet attestation signed by the wallet provider; not enforced in verifiably-go (would require verifier-side attestation validation)
Holder key binding proof (cnf claim) โš ๏ธ enforced by walt.id wallet-api; verifiably-go doesn't verify cnf independently
Key binding JWT (kb-jwt) over vp_token โš ๏ธ present in SD-JWT VC wire format; verifiably-go extracts claims without re-verifying kb-jwt signature

5. Security

Requirement Status Notes
TLS for all endpoints (HAIP ยง4.1) โœ… enforced by Caddy in subdomain mode; localhost mode exempt per spec
Authorization Code PKCE โœ… PendingPKCE stored in session, passed through OIDC flow
DPoP token binding (HAIP RECOMMENDED) โš ๏ธ not enforced by verifiably-go; delegated to walt.id
iss claim validation in responses โš ๏ธ verified by walt.id; verifiably-go trusts the adapter's success/error
Status list revocation (HAIP ยง7.2) โœ… W3C BSL 2023 + IETF Token Status List both implemented
Credential expiry (exp claim) โš ๏ธ set by walt.id; not enforced by verifiably-go on fetch

6. Identified Gaps โ€” Priority Order

โŒ Gap 1: response_mode=direct_post.jwt (JARM)

Requirement: HAIP ยง5.5 โ€” response MUST be JWT-encrypted to the verifier's public key.
Current state: direct_post (plain JSON body, no encryption).
Risk: Credential claims in transit are visible to redirect intermediaries.
Fix path:

  1. Upgrade walt.id to a version that supports JARM (check release notes for direct_post.jwt).
  2. Provision the verifier's encryption key (ECDH-ES+A256KW) and register it in the verifier metadata.
  3. verifiably-go passes the response_mode parameter through to RequestPresentation โ€” no code change needed once walt.id supports it.

Effort: M โ€” depends on walt.id upstream support.

โŒ Gap 2: client_id_scheme=x509_san_dns

Requirement: HAIP ยง4.3 โ€” verifiers in high-assurance flows MUST authenticate with an X.509 certificate whose SAN DNS matches the client_id.
Current state: client_id is the verifier's redirect_uri (scheme redirect_uri).
Risk: Wallet cannot distinguish a legitimate verifier from a phishing site without a certificate.
Fix path:

  1. Issue a TLS certificate for the verifier subdomain (already done via Caddy/Let's Encrypt in subdomain mode).
  2. Configure walt.id verifier-api client_id_scheme = "x509_san_dns" and point to the cert.
  3. verifiably-go passes client_id through the OID4VPTemplate; add ClientIDScheme field to the template type.

Effort: M โ€” config change in walt.id + schema extension in verifiably-go.

โŒ Gap 3: wallet_attestation

Requirement: HAIP ยง6 โ€” issuer MUST validate wallet attestation JWT before issuing.
Current state: attestation not required or validated.
Risk: Any OAuth client that has the authorization code can impersonate a conformant wallet.
Fix path:

  1. Add wallet_attestation validation to the issuance flow in APIIssue / walt.id adapter.
  2. Trust anchor (wallet provider public key) must be fetched from a trusted registry or pinned.

Effort: Lโ€“XL (depends on whether a public wallet attestation registry exists for the target wallets).


7. What's Already HAIP-Compliant

  • SD-JWT VC credential format end-to-end (issue โ†’ present โ†’ verify disclosed fields)
  • OID4VCI Pre-auth + Authorization Code flows via walt.id
  • OID4VP with DIF PE presentation_definition
  • W3C BSL 2023 + IETF Token Status List revocation
  • PKCE in OIDC authorization flows
  • TLS termination via Caddy in production mode
  • Nonce freshness (one-time use enforced via session state)
  • Per-issuer credential scoping (OwnerKey)

8. Recommended Closure Plan

Priority Item Version target
P1 Upgrade walt.id to a release with direct_post.jwt support Next walt.id release after 0.18.2
P1 Configure client_id_scheme=x509_san_dns in verifier-api Same release cycle
P2 Add ClientIDScheme field to OID4VPTemplate and thread it through RequestPresentation verifiably-go sprint
P3 Research wallet attestation registry for target wallets (EUDI, inji) Architecture spike
P3 Add kb-jwt signature verification in verifier adapter After trust anchor decision
Source: docs/haip-conformance.md