OID4VP feature support
A feature-by-feature reference for how the MATTR Pi Holder SDKs support OpenID for Verifiable Presentations (OID4VP) as profiled by ISO/IEC 18013-7 Annex B when presenting mDocs to a remote verifier.
Overview
This page is a feature-by-feature reference for how the MATTR Pi Holder SDKs support OpenID for Verifiable Presentations (OID4VP) when acting as a wallet that presents mDocs to a remote verifier.
MATTR's remote presentation implementation follows the OID4VP profile defined by ISO/IEC 18013-7:2025 Annex B, not the OID4VP 1.0 specification directly. Annex B profiles OID4VP draft 18, April 2023, so several parameter names on this page differ from OID4VP 1.0. See Relationship to OID4VP 1.0 for a translation.
It complements the remote presentation overview, which explains how remote presentation works. Use this page when you need to know whether a specific OID4VP feature is available in the Holder SDK before you design a wallet integration.
If you are building a verification solution, see the OID4VP feature support (Verifier) page instead.
How to read this page
Each feature is given one of the following support statuses:
- Supported: Implemented and available for use.
- Partial: Implemented with a specific limitation, described in the notes.
- Not supported: Not currently implemented. Some fields may be parsed for specification compliance without any behavior attached.
- Not applicable: Not relevant to the wallet role.
The Spec column cites the relevant clause of
ISO/IEC 18013-7:2025 Annex B unless the citation names
another specification. n/a means the feature is either a MATTR SDK convenience or a parameter
that Annex B does not define at all.
Support statuses reflect the latest versions of the iOS and Android SDKs. The React Native SDK wraps the native SDKs, so its support matches the platform it runs on. Where iOS and Android genuinely differ, the notes say so. If you need clarification on any feature, contact us.
Wallet invocation and request delivery
| Feature | Spec | Status | Notes |
|---|---|---|---|
Invocation via the ISO 18013-7 scheme (mdoc-openid4vp://) | B.2, B.3.2.3.3 | Supported | Your application registers the scheme. See URI scheme handling. |
| Invocation via a private-use URI scheme | n/a | Supported | Your application registers its own reverse-domain scheme, for example com.example.wallet://. |
| Invocation via a claimed HTTPS scheme | n/a | Supported | Uses App Links on Android and Universal Links on iOS. |
Authorization request by reference (request_uri) | B.4.2.3 | Supported | Required. The SDK retrieves the request object from request_uri with an HTTP GET. |
| Authorization request by value | B.4.2.3 | Not supported | The request URI must carry client_id, client_id_scheme and request_uri. A request that inlines the request object is rejected. |
request_uri_method (get or post) | n/a | Not supported | Retrieval is always a GET. This parameter is defined by OID4VP 1.0 § 5.10 and is not part of Annex B. |
| Signed request object | B.4.2.3 | Supported | Required. The SDK validates the JWS signature before the session is created. |
| Unsigned authorization request | B.4.2.3 | Not supported | An unsigned request is rejected. |
Request object typ header | n/a | Not supported | The SDK does not read or validate the typ header. OID4VP 1.0 § 5.10 expects oauth-authz-req+jwt. Setting it is good practice for other wallets, but the SDK neither requires it nor rejects a request without it. |
Request object exp and nbf claims | n/a | Partial | Android rejects an expired or not-yet-valid request object, allowing for clock skew. iOS does not read either claim, so an expired request object is still processed. Do not rely on the wallet to enforce your request lifetime. |
wallet_nonce request object replay protection | n/a | Not supported | Defined by OID4VP 1.0 § 5.10 alongside request_uri_method. |
Client identifier and verifier authentication
The Holder SDK accepts exactly one client identifier scheme. Verifier authentication is not optional on this path, because the request object must always be signed and validated. What you control is how strictly that signature must chain to a certificate you trust ahead of time. See Handling verifier authentication.
| Feature | Spec | Status | Notes |
|---|---|---|---|
client_id_scheme request parameter | B.4.2.3 | Supported | Required on the request URI. A request without it is rejected. |
x509_san_dns | B.4.2.3 | Supported | The only accepted scheme. The x5c leaf certificate must carry a dNSName Subject Alternative Name matching client_id. |
x509_san_uri | n/a | Not supported | Defined by earlier OID4VP drafts and removed in OID4VP 1.0. |
x509_hash | n/a | Not supported | Introduced by OID4VP 1.0 § 5.9.3. |
redirect_uri | n/a | Not supported | |
verifier_attestation | n/a | Not supported | |
openid_federation | n/a | Not supported | |
decentralized_identifier (did in earlier drafts) | n/a | Not supported | |
| Pre-registered client | n/a | Not supported | client_id_scheme is mandatory, so the no-scheme fallback does not apply. |
| Validation against a trusted verifier certificate | n/a | Supported | The SDK validates the request signature against trusted verifier root certificates stored on the device and reports a Certificate outcome. |
| Validation against published verifier metadata | B.3.3.1 | Supported | When no trusted certificate matches, the SDK resolves the verifier's client metadata and validates against the keys published there, reporting a Domain outcome. This path resolves the signing key by kid, so the request object's JWS protected header must carry a kid that matches a key in the published jwks. A request signed with only an x5c chain and no kid cannot validate by domain. |
| Requiring a trusted verifier | n/a | Supported | The requireTrustedVerifier option rejects a request that validates only by domain. |
| Wallet metadata endpoint | B.3.2.2, B.3.2.3 | Not supported | The SDK neither publishes nor serves wallet metadata, so a verifier cannot discover its capabilities dynamically. Verifiers rely on the static configuration implied by the mdoc-openid4vp:// scheme. |
Credential query
| Feature | Spec | Status | Notes |
|---|---|---|---|
presentation_definition by value | B.4.2.3.3 | Supported | Presentation Exchange is the query language on this path. |
presentation_definition_uri | n/a | Not supported | The presentation definition must be inline in the request object. |
| Multiple input descriptors in one request | B.4.2.3.3 | Supported | Each input descriptor becomes a separate credential request, matched by doctype. One credential is returned per doctype. See Returning more than one credential. |
limit_disclosure | B.4.2.3.3 | Supported | Required in the request. Only the requested data elements are disclosed. |
intent_to_retain | B.4.2.3.3 | Supported | Required on every field. Read per claim and surfaced to your application so your consent screen can show it. |
presentation_submission in the response | B.4.3.3 | Supported | The SDK builds a descriptor map covering every input descriptor in the request. |
DCQL (dcql_query) | n/a | Not supported | DCQL replaces Presentation Exchange in OID4VP 1.0 and is not used on this path. Android does use DCQL over the Digital Credentials API, covered below. |
scope-based presentation request | n/a | Not supported | |
transaction_data | n/a | Not supported | Introduced by OID4VP 1.0 § 5.1. |
verifier_info | n/a | Not supported | Introduced by OID4VP 1.0 § 5.11. |
trusted_authorities | n/a | Not supported | Issuer trust is enforced through the SDK's trusted issuers configuration rather than signaled in the request. |
What the presentation definition must contain
The SDK reads a narrow subset of Presentation Exchange, and every member in the following table is required. A request that omits one is rejected before the holder sees a consent screen, so check these first if a request fails with no obvious cause.
| Member | Requirement |
|---|---|
input_descriptors[].id | Must be the doctype you are requesting, for example org.iso.18013.5.1.mDL. The SDK uses this value directly as the doctype when it matches stored credentials, so an opaque identifier such as a UUID matches nothing and returns no credential. |
input_descriptors[].format.mso_mdoc | Required. Its alg array is required on iOS and optional on Android, so always include it. |
input_descriptors[].constraints.limit_disclosure | Required. Set it to required. |
input_descriptors[].constraints.fields[].path | Required, and must be a single-element array holding exactly $['namespace']['element'], for example $['org.iso.18013.5.1']['family_name']. A field carrying more than one path, or a path in any other shape, is skipped. |
input_descriptors[].constraints.fields[].intent_to_retain | Required on every field. There is no default. |
A descriptor whose paths all fail to parse behaves differently per platform
If none of an input descriptor's field paths parse, Android drops the descriptor and does not request that credential at all, while iOS keeps it and requests the doctype with no data elements. Validate your paths rather than relying on either behavior.
Response
| Feature | Spec | Status | Notes |
|---|---|---|---|
response_type value vp_token | B.4.3.2 | Supported | |
Response mode direct_post.jwt | B.4.2.3 | Supported | The only accepted response mode. Annex B mandates it. |
Response mode direct_post | n/a | Not supported | An unencrypted direct post is rejected, because encryption is mandatory. |
Response mode fragment or query | n/a | Not supported | |
response_uri | B.4.2.3 | Supported | The SDK posts the response as application/x-www-form-urlencoded with a single response field carrying the encrypted JWT. |
vp_token | B.4.3.2 | Supported | A JSON string carrying a single base64url-encoded ISO DeviceResponse, never an object keyed by credential identifier. See Returning more than one credential. |
state | B.4.3.2 | Supported | Echoed back unchanged. Android requires 1 to 8192 URL-safe characters and rejects anything outside that range. iOS does not check. |
nonce | B.4.2.3 | Supported | Android requires 11 to 512 URL-safe characters and rejects anything outside that range. iOS does not check. Stay inside the range for both platforms. |
| Verifier-supplied redirect after the response | B.4.3.2 | Supported | The SDK reads the redirect_uri returned by the response endpoint, returns it to your application, and by default opens it so the user lands back where they started. |
| Error response to the verifier | B.4.3.2 | Partial | The SDK reports failures to your application. It does not post an OID4VP error response back to response_uri. |
Returning more than one credential
vp_token is a JSON string, not an object. It always carries exactly one base64url-encoded ISO
DeviceResponse, however many credentials the request asked for. It is never keyed by credential
identifier the way OID4VP 1.0 keys vp_token by DCQL credential id.
When a request carries several input descriptors, the wallet returns several documents inside that
one DeviceResponse. Four things to know when you match them back to your request:
- Match on each document's
docType, not onpresentation_submission. Everydescriptor_mapentry usespath: "$", which points at the wholevp_token, so the descriptor map cannot tell you which document answers which input descriptor. - One credential per doctype. Two input descriptors naming the same doctype cannot both be satisfied.
- A requested doctype the holder does not have becomes a
documentErrorsentry, carrying the ISO error code for data not returned, rather than a failed response. ReaddocumentErrorsas well asdocuments. - Disclosed elements are the intersection of what you requested and what the credential holds.
A requested element the credential does not carry is reported in that document's own
errorsmap, so a response can legitimately hold fewer data elements than you asked for. Rejecting a response solely because it discloses fewer claims than requested will reject valid presentations. Read the per-documenterrorsinstead.
Response encryption
Response encryption is mandatory. There is no configuration that disables it, because
direct_post.jwt is the only accepted response mode.
| Feature | Spec | Status | Notes |
|---|---|---|---|
| Encrypted authorization response | B.3.3.1, B.4.2.3 | Supported | The response is an encrypted JWT carried in the response form field. |
authorization_encrypted_response_alg value ECDH-ES | B.3.3.1 | Supported | The only accepted key agreement algorithm. Any other value is rejected. |
authorization_encrypted_response_enc value A256GCM | B.3.3.1 | Supported | |
authorization_encrypted_response_enc value A128GCM | B.3.3.1 | Supported | |
| AES-CBC content encryption | n/a | Not supported | A128CBC-HS256 and A256CBC-HS512 are rejected on this path. |
Verifier encryption key from client_metadata.jwks | B.3.3.1 | Supported | The SDK selects the first key with encryption use and the ECDH-ES algorithm. Both members must be present on the JWK. If no such key is present the request is rejected. Publish a single encryption key if you need certainty about which one is used. |
kid echoed on the response | B.3.3.1 | Supported | The SDK sets kid on the response's JWE protected header to the kid of the verifier key it selected, so you can identify the matching decryption key. A JWK published without a kid produces a response without one. |
apu and apv JWE headers | B.4.4 | Supported | apv carries the authorization request nonce and apu carries the mdoc-generated nonce. Both are required by the session transcript. |
| Signed authorization response | n/a | Not supported | The response is encrypted but not separately signed. Holder binding is proven inside the DeviceResponse. |
What client_metadata must contain
client_metadata is required in the request object, and the SDK reads it using the ISO 18013-7
Annex B member names. All four members in the following table are required, and a request missing
any one of them is rejected before verification starts.
| Member | Requirement |
|---|---|
jwks | An EC key set holding at least one key with encryption use and the ECDH-ES algorithm. |
authorization_encrypted_response_alg | Must be ECDH-ES. Any other value is rejected. |
authorization_encrypted_response_enc | Must be A256GCM or A128GCM. |
vp_formats | Required, and must hold an mso_mdoc entry. The nested alg array is optional. |
OID4VP 1.0 metadata names are not accepted on this path
A verifier that publishes the OID4VP 1.0 names, such as
encrypted_response_enc_values_supported or vp_formats_supported, has its request rejected.
Unknown members are ignored rather than translated, so the request then fails for missing required
members, and it fails before any key agreement is attempted. Use the Annex B names above.
Session transcript
| Feature | Spec | Status | Notes |
|---|---|---|---|
ISO 18013-7 OID4VPHandover | B.4.4 | Supported | Built as [clientIdHash, responseUriHash, nonce], where each hash covers the value together with a freshly generated mdoc nonce. |
| mdoc-generated nonce | B.4.4 | Supported | A 32 character random value, sent to the verifier in the JWE apu header. |
OID4VP 1.0 OpenID4VPHandover | OID4VP 1.0 B.2.6.1 | Not supported | OID4VP 1.0 defines a different structure under a very similar name. See Relationship to OID4VP 1.0. |
Credential formats
The MATTR Pi Holder SDKs are mDocs Holder SDKs. Only the ISO mdoc format (mso_mdoc) is
handled end to end.
| Format | Spec | Status | Notes |
|---|---|---|---|
ISO mdoc / mDL (mso_mdoc) | B.4.2.3.3 | Supported | The only format presented by the Holder SDK. |
IETF SD-JWT VC (dc+sd-jwt) | n/a | Not supported | |
W3C VC JWT (jwt_vc_json) | n/a | Not supported | |
W3C VC JSON-LD (ldp_vc) | n/a | Not supported |
Digital Credentials API
The Digital Credentials API is a separate presentation path from the mdoc-openid4vp:// redirect
flow described above, and the two platforms implement different ISO 18013-7 annexes. Android
presents over OID4VP, and iOS presents the ISO mdoc protocol directly with no OID4VP involved.
Plan for both if you ship on both platforms. See the
Digital Credentials API overview for the integration guides.
| Feature | Spec | Status | Notes |
|---|---|---|---|
| Android: OID4VP over the Digital Credentials API | 18013-7 Annex D | Supported | Presented through Android Credential Manager. |
Android: protocol openid4vp-v1-unsigned | OID4VP 1.0 A.1 | Supported | |
Android: protocol openid4vp-v1-signed | OID4VP 1.0 A.1 | Supported | The signed request's certificate is validated against the verifier certificates trusted on the device. |
Android: protocol openid4vp-v1-multisigned | OID4VP 1.0 A.1 | Not supported | |
| Android: query language | OID4VP 1.0 § 6 | Partial | DCQL, not Presentation Exchange. Only credentials with format, meta.doctype_value and claims.path are read, and a single credential is processed per request. credential_sets, claim_sets, values, multiple and trusted_authorities are not supported. |
Android: response mode dc_api.jwt | OID4VP 1.0 A.2 | Supported | Encrypted response. |
Android: response mode dc_api | OID4VP 1.0 A.2 | Supported | Unencrypted response. Unlike the redirect path, encryption is not mandatory here. |
Android: expected_origins | OID4VP 1.0 A.2 | Not supported | |
| Android: handover | OID4VP 1.0 B.2.6.2 | Supported | OpenID4VPDCAPIHandover, computed over the origin, nonce and verifier key thumbprint. |
| iOS: OID4VP over the Digital Credentials API | 18013-7 Annex D | Not supported | iOS implements Annex C instead. |
| iOS: ISO mdoc retrieval over the Digital Credentials API | 18013-7 C.1 to C.5 | Supported | Requires iOS 26.0 or later and an Identity Document Services app extension. The request is a CBOR DeviceRequest with EncryptionInfo, and the response is HPKE encrypted. No OID4VP request is involved. |
| iOS: handover | 18013-7 C.5 | Supported | The dcapi handover, computed over the encryption info and origin. |
Relationship to OID4VP 1.0
If you are working from the OID4VP 1.0 specification rather than ISO 18013-7, the redirect path described on this page will not match what you read. Annex B profiles OID4VP draft 18, April 2023. This table maps the differences that affect a wallet or verifier implementer.
| Concept | ISO 18013-7 Annex B, used by the redirect path | OID4VP 1.0 |
|---|---|---|
| Client identifier scheme | A separate client_id_scheme request parameter, with client_id carrying the bare DNS name | The scheme is a prefix inside client_id itself, for example x509_san_dns:verifier.example.com |
| Scheme discovery | Wallet advertises client_id_schemes_supported | Wallet advertises client_id_prefixes_supported, defaulting to pre-registered |
| Scheme names | x509_san_dns, x509_san_uri, did | x509_san_uri removed, x509_hash added, did renamed to decentralized_identifier, origin reserved |
| Query language | Presentation Exchange, using presentation_definition and presentation_submission | DCQL, using dcql_query. Presentation Exchange is removed entirely |
| Response encryption metadata | authorization_encrypted_response_alg and authorization_encrypted_response_enc | A single encrypted_response_enc_values_supported list, with the key agreement algorithm taken from the JWK |
| mdoc session transcript | OID4VPHandover, a three element array of [clientIdHash, responseUriHash, nonce] using an mdoc-generated nonce | OpenID4VPHandover, a labeled two element array whose hash covers [clientId, nonce, jwkThumbprint, responseUri] |
| Wallet invocation scheme | mdoc-openid4vp://, registered by Annex B | openid4vp://. mdoc-openid4vp:// does not appear in OID4VP 1.0 |
The two handover structures are not interchangeable
ISO 18013-7 Annex B and OID4VP 1.0 both define an mdoc handover under nearly the same name, but
the structures differ. A verifier that builds the OID4VP 1.0 OpenID4VPHandover for a redirect
flow will produce a session transcript the Holder SDK cannot reproduce, and device
authentication will fail. Match the profile your wallet and verifier have agreed on.
Note that Android's Digital Credentials API path does use OID4VP 1.0 vocabulary, including DCQL
and the OpenID4VPDCAPIHandover. The two baselines coexist in the same SDK on different paths.
Not currently supported
At a glance, the following features are not currently supported by the Holder SDK on the
mdoc-openid4vp:// redirect path:
- Authorization request by value (B.4.2.3)
request_uri_method, including thepostmethod (OID4VP 1.0 § 5.10)- Every client identifier scheme other than
x509_san_dns(B.4.2.3) - Unsigned authorization requests (B.4.2.3)
- Validation of the request object
typheader (OID4VP 1.0 § 5.10) - Serving wallet metadata for dynamic capability discovery (B.3.2.2, B.3.2.3)
presentation_definition_uri(B.4.2.3.3)- DCQL on the redirect path (OID4VP 1.0 § 6)
- Unencrypted responses, including response mode
direct_post(B.4.2.3) - AES-CBC content encryption algorithms (B.3.3.1)
transaction_data(OID4VP 1.0 § 5.1)verifier_info(OID4VP 1.0 § 5.11)trusted_authorities(OID4VP 1.0 § 6.1.1)- Credential formats other than mDocs (
mso_mdoc)
Related
How would you rate this page?
Last updated on