OID4VCI
OID4VCI
Section titled “OID4VCI”ProtocolSoup’s OID4VCI Issuer and Wallet implementations are OpenID Certified™ through the OpenID Foundation certification programme (HAIP, SD-JWT VC, and mdoc). Certification applies to the named versions and profiles, not every ProtocolSoup feature.
Standards
Section titled “Standards”- OpenID for Verifiable Credential Issuance 1.0 (final)
- OAuth 2.0 Authorization Framework (token and grant semantics)
- RFC 8414 OAuth 2.0 Authorization Server Metadata
- OAuth 2.0 Attestation-Based Client Authentication (draft-ietf-oauth-attestation-based-client-auth)
- OID4VCI 1.0 Appendix D Key Attestation
- RFC 9449 OAuth 2.0 Demonstrating Proof of Possession (DPoP), opt-in
- OpenID4VC High Assurance Interoperability Profile (HAIP) 1.0 (final)
- SD-JWT VC profile (
dc+sd-jwtcredential format) - W3C Verifiable Credentials Data Model 1.1 / 2.0 (
jwt_vc_json,jwt_vc_json-ld,ldp_vcformats) - W3C VC Data Integrity 1.0 (
ecdsa-rdfc-2019,eddsa-rdfc-2022cryptosuites forldp_vc) - ISO/IEC 18013-5 mobile driving licence (
mso_mdoccredential format, doctypeorg.iso.18013.5.1.mDL)
Available Flows
Section titled “Available Flows”| Flow ID | Name | Steps | Description |
|---|---|---|---|
oid4vci-pre-authorized |
Pre-Authorized Code | 6 | Create Credential Offer, then observe wallet→issuer metadata, token, nonce, proof, and credential hops |
oid4vci-pre-authorized-tx-code |
Pre-Authorized + tx_code | 6 | Same stages with mandatory tx_code on the token request |
oid4vci-deferred-issuance |
Deferred Issuance | 8 | Same stages plus deferred_credential polling until credentials are ready |
oid4vci-issuer-initiated |
Issuer-Initiated Offer | 4 | Create an authorization_code Credential Offer with a fresh issuer_state. Under Advanced, optionally paste a Credential Offer Endpoint for a real HTTPS GET delivery, or leave it blank for an openid-credential-offer:// invocation/QR. Then click Check Result to observe real issuer-observed PAR, token, and credential issuance milestones. Looking Glass does not redeem the code in-browser. |
Demo Scenarios
Section titled “Demo Scenarios”- Pre-Authorized Issuance – Looking Glass creates a Credential Offer, then surfaces each real wallet→issuer hop (Credential Issuer Metadata, Token Request, Nonce Request, proof JWT, Credential Request/Response) from the wallet’s protocol transcript. The default credential is the ISO/IEC 18013-5 mobile driving licence (
mso_mdoc). Format and HAIP are independent selectors. HAIP issues with client and key attestation; the hosted wallet supplies that material. A 400 on import without attestation env is the real HAIP gate on a self-hosted wallet. - Pre-Authorized + tx_code – Same glass-box stages with mandatory
tx_codeon the token request - Deferred Issuance Polling – Same stages plus Deferred Credential Poll until the credential is ready
- Issuer-Initiated Offer – Build an
authorization_codeoffer withissuer_state. Under Advanced, paste an optional wallet Credential Offer Endpoint; the issuer then delivers the offer with a real HTTPS GET (credential_offerquery parameter; 2xx/3xx accepted without following redirects). Otherwise Looking Glass exposes anopenid-credential-offer://invocation URI/QR. Looking Glass then reuses the OID4VP wallet-handoff chrome (awaiting_user+ “Check Result”): each click checks a separate opaquestatus_urionce for whether the issuer has received the wallet’s validated PAR, issued the access token, and issued the credential, or reports the offer context has expired. Looking Glass does not complete PAR/token/credential in-browser. When the wallet PAR uses scope only (for examplevc:mdl), the issuer binds authorization to the intersection with the offer’s credential configurations.
Credential Details
Section titled “Credential Details”| Property | Value |
|---|---|
| Credential configuration selection | Wallet chooses from credential_configurations_supported (dc+sd-jwt / mso_mdoc). The default and lead entry is the mDL (MobileDrivingLicenceMsoMdoc); omitting an explicit configuration selects it. |
| Credential formats | Advertised: mso_mdoc (ISO/IEC 18013-5 mDL, default), dc+sd-jwt (SD-JWT VC). Also issuable by id: jwt_vc_json, jwt_vc_json-ld, ldp_vc (W3C Data Integrity). |
| Proof container | OID4VCI 1.0 proofs object keyed by proof type (for example, {"jwt":["<compact-jws>", "..."]}). Issuer metadata advertises batch_credential_issuance.batch_size (20); each JWT in the array receives one credential copy of the same Credential Dataset bound to that proof key. Other proof types are not advertised; the removed draft proof parameter is ignored. |
mso_mdoc device key binding |
Proof JOSE header jwk must be an EC P-256 key; it is bound into the MSO deviceKeyInfo.deviceKey as a COSE_Key. Issuer metadata advertises the credential signing algorithm as COSE identifier -7, while the JWT proof algorithm remains JOSE ES256. Issued mDLs include the mandatory portrait as a valid, identity-derived stylized JPEG rather than presenting it as a real person’s photograph. |
| Proof JWT header type | openid4vci-proof+jwt |
| Proof JWT | Protected header contains exactly one key reference (jwk is supported); payload requires aud, nonce, and iat. Anonymous pre-authorized clients omit iss. |
| Deferred issuance indicator | transaction_id returned by credential endpoint (e.g., an opaque identifier such as "txn_...") |
Pre-Authorized Code Issuance Flow (OID4VCI §4, §6.1, §7)
Section titled “Pre-Authorized Code Issuance Flow (OID4VCI §4, §6.1, §7)”- Resolve Credential Offer — Wallet receives
credential_offer_uriout-of-band and fetches the credential offer object from the Credential Issuer. Offer containscredential_issuer,credential_configuration_ids, andgrants.urn:ietf:params:oauth:grant-type:pre-authorized_code. - Discover Issuer Metadata — Wallet fetches Credential Issuer Metadata via OID4VCI §12.2.2 well-known insertion (
https://host/.well-known/openid-credential-issuer{path}), preserving a trailing slash on the issuer path when present. - Token Request — Wallet calls token endpoint with
grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code,pre-authorized_code, andtx_codewhen required by the offer grant. - Token Response and Nonce Request — Authorization Server returns
access_token,token_type, andscope(if applicable). The Wallet then obtainsc_noncefrom the advertised Nonce Endpoint. - Credential Request — Wallet submits
credential_configuration_idandproofs: { "jwt": ["...", ...] }with one or more proof JWTs (up tobatch_credential_issuance.batch_size) bound to the activec_nonceand the credential issuer audience. Multiple proofs request multiple copies of the same Credential Dataset, each bound to a distinct proof key. - Credential Response — Issuer validates proof key binding, nonce freshness, and audience/subject constraints, then returns:
- Immediate: a
credentialsarray (one entry per accepted proof, never more than proofs submitted) and anotification_id, or - Deferred:
transaction_id— wallet then pollsdeferred_credentialuntil it receives thecredentialsarray andnotification_id.
- Immediate: a
- Notification — Wallet reports
credential_accepted,credential_failure, orcredential_deletedto the advertisednotification_endpoint. The identifier is bound to the issuing access token and exact retries are idempotent.
Authorization Code Flow
Section titled “Authorization Code Flow”In addition to pre-authorized_code, the token endpoint accepts
grant_type=authorization_code. The Authorization Server (the mockidp-backed
/oidc/authorize and /oid4vci/token) is discoverable via RFC 8414 metadata:
- Wallet reads
authorization_serversfrom the Credential Issuer Metadata (defaults to the issuer’s own identifier). - Wallet fetches
{authorization_server}/.well-known/oauth-authorization-server(RFC 8414 Section 3.1 well-known URI insertion — for issuerhttps://host/oid4vcithis resolves tohttps://host/.well-known/oauth-authorization-server/oid4vci; a trailing slash on the issuer path is stripped). The wallet does not fall back toopenid-configurationfor OID4VCI. Discovery yieldsauthorization_endpoint,token_endpoint,grant_types_supported,code_challenge_methods_supported(S256),authorization_response_iss_parameter_supported(true, RFC 9207), andtoken_endpoint_auth_methods_supported. Scope-only authorization does not inventauthorization_detailsin the Token Response; RAR requests still receivecredential_identifiersfor the requested configurations. - HAIP wallets push the request to the advertised RFC 9126
pushed_authorization_request_endpointwith client attestation and PKCE S256. A PAR body must not includerequest_uri(RFC 9126 §2.1); the endpoint rejects it with HTTP 400invalid_request. Authorization-code DPoP binding may be established via aDPoPproof, thedpop_jktform parameter (RFC 9449 Section 10.1), or both when the JWK thumbprints agree; a mismatch is rejected withinvalid_dpop_proof. Wallets may still introduce DPoP only at token redemption under the HAIP profile. The resultingrequest_uricarries the exact client, redirect, and credential configuration bindings into authorization. Token redemption by a different attested client returns HTTP 400invalid_grant(OIDCC §3.1.3.4 / FAPI2 SP), including when that second client has not previously called PAR. - Wallet drives the standard OAuth 2.0 authorization code flow against
authorization_endpointwith onlyclient_idandrequest_uriafter PAR (FAPI2 SP Final §5.3.3.2), then exchanges the code attoken_endpointwith the same client attestation authentication used at PAR, receivingaccess_tokenbefore requestingc_noncefrom the Nonce Endpoint. PARrequest_urivalues stay usable across authorize page loads and are consumed only when authorization completes (FAPI 2.0 SP §5.3.2.2 Note 3); PAR-backed requests never silent-SSO via an existing session cookie and require an explicit Continue (or password login) after the preload visit.
This path is implemented at the issuer HTTP/API layer and by the hosted wallet
reference client (protocolsoup-wallet: POST /api/import,
GET /api/oid4vci/callback). Looking Glass pre-authorized executors create the
issuer offer, then delegate redemption to the wallet harness via
POST /api/import (token, proof, credential, and deferred polling run in the
wallet — not in the browser). The issuer-initiated Looking Glass flow
(oid4vci-issuer-initiated) creates and optionally delivers an
authorization_code offer, then observes issuer-side PAR/token/credential
milestones via status_uri; it does not impersonate the wallet. Pointing Looking
Glass Advanced credential_offer_endpoint at the wallet (with HAIP
attestation env configured when the offer targets a HAIP configuration) is how a
wallet-driven authorization-code path is exercised.
Authorization requests can carry openid_credential authorization_details.
The issuer validates each requested configuration, binds the approved details
to the authorization code and access token, returns stable
credential_identifiers in the token response, and authorizes credential
requests by credential_identifier. A credential identifier that is unknown
or not bound to the access token is rejected with
unknown_credential_identifier (OID4VCI §8.3.1.2), including when the Token
Response never returned credential_identifiers. A replayed authorization
code returns invalid_grant and revokes the access token previously issued
from that code so credential (and related) resource endpoints reject it with
invalid_token (RFC 6749 Section 4.1.2).
HAIP issuance building blocks
Section titled “HAIP issuance building blocks”The issuer implements the following HAIP-related issuance controls as opt-in, trust-anchor-gated (or otherwise explicitly enabled) API features. Named certified ProtocolSoup versions and OID4VCI profiles are listed on the trust page; this section describes the controls in the running demo, not a blanket claim for every deployment.
The hosted wallet reference client drives client attestation, key attestation,
DPoP, and credential-response encryption together when HAIP attestation
material is configured (WALLET_CLIENT_ATTESTATION_ATTESTER_JWK_JSON and
WALLET_CLIENT_ATTESTATION_KEY_ATTESTATION_JWK_JSON, plus related
WALLET_OID4VCI_ATTESTED_CLIENT_ID / WALLET_CLIENT_ATTESTATION_ISSUER /
WALLET_KEY_ATTESTATION_* settings). Looking Glass pre-authorized executors
delegate redemption to that wallet path via /api/import rather than minting
attestation and DPoP proofs in the browser. Issuer-initiated Looking Glass
observes a real wallet conversation via status_uri. The unattested Final
flow remains unaffected by default.
- Sender-constrained access tokens (RFC 9449 DPoP). The token endpoint
accepts an optional
DPoPproof header; when present, the issued access token is bound to the proof’s key via acnf.jktclaim, withtoken_type: DPoPin the response instead ofBearer. Theauthorization_codegrant also issues a refresh token; when Client Attestation was used that refresh token is bound to the Client Instance Key (OAuth2-ATCA §10.3) and not to the DPoP key (RFC 9449 §5 treats attestation like other client authentication). When DPoP was used without attestation, the refresh token is DPoP-bound. Refresh tokens are not rotated on use (FAPI2 SP Final §5.3.2.1-9); FAPI2 may still present a new DPoP proof key on refresh. Pre-authorized code grants do not issue refresh tokens. A DPoP-bound access token is then rejected at the credential, nonce, deferred_credential, and notification endpoints unless presented asAuthorization: DPoP <token>with a matching, unreplayed DPoP proof — presenting it as a bare bearer token fails outright, never silently downgrades. A server-provided nonce challenge (DPoP-Nonceresponse header,use_dpop_nonceerror) is available independently at the token endpoint (SHOWCASE_DPOP_NONCE_REQUIRED) and at the resource endpoints (SHOWCASE_DPOP_RESOURCE_NONCE_REQUIRED), off by default. This issuer’s own RFC 8414 metadata advertisesdpop_signing_alg_values_supportedfor the accepted proof algorithms. Only JWT access tokens can be bound; opaque/reference token binding is out of scope. - Client attestation (OAuth 2.0 Attestation-Based Client Authentication).
The PAR and token endpoints accept an
OAuth-Client-Attestation+OAuth-Client-Attestation-PoPheader pair as an alternative toclient_secret/Basic auth. The attestation JWT’sx5cchain is verified against a configured trust anchor, itscnf.jwkbecomes the Client Instance Key that must sign the PoP JWT, and the PoP’sjtiis single-use. When both headers are present, they are the authentication verdict for the request — a failed attestation is never silently downgraded to a weaker method. The hosted wallet treats each HTTP attempt as a new authenticated request: on a DPoPuse_dpop_nonceretry at PAR or token, it keeps the Client Attestation JWT and mints a fresh PoP with a newjti(OAuth2-ATCA single-use PoPjti). Credential and other resource requests similarly retry when the RS returns HTTP 401 (or 400) withuse_dpop_nonceand aDPoP-Nonceheader (RFC 9449). The attestedsubbecomes the authoritativeclient_id. Advertised in AS metadata’stoken_endpoint_auth_methods_supportedasattest_jwt_client_authonly once a trust anchor is configured, alongside ES256 inclient_attestation_signing_alg_values_supportedandclient_attestation_pop_signing_alg_values_supported. - Key attestation (OID4VCI 1.0 Appendix D). Credential configurations may
set
key_attestations_required(advertised underproof_types_supported.jwtin Credential Issuer Metadata). For those configurations, the proof JWT’s JOSE header must carry akey_attestationJWT (typ: key-attestation+jwt) whosex5cchain is verified against a configured trust anchor, and whoseattested_keysmust include the proof’s JOSE-headerjwkholder key and satisfy any requiredkey_storage/user_authenticationattack-potential levels. HAIP batch issuance from the hosted wallet puts every proof key in one Key Attestation JWT (HAIP 1.0 Section 4.5.1); each jwt proof repeats that JWT in itskey_attestationheader. - Encrypted credential responses. A wallet may include a
credential_response_encryptionobject (jwk,enc) on the Credential or Deferred Credential Request. When present and valid, the response is returned as a compact JWE (Content-Type: application/jwt) — ECDH-ES key agreement to the wallet’s ephemeral key, then AES-GCM content encryption (A128GCMorA256GCM) — instead of plain JSON. Advertised in Credential Issuer Metadata’scredential_response_encryptionobject;encryption_requiredstaysfalse. - Encrypted credential requests. Credential Issuer Metadata advertises an
ECDH-ES public key plus
A128GCM/A256GCMincredential_request_encryption. The Credential Endpoint and Deferred Credential Endpoint accept the compact JWE asapplication/jwt, decrypt it with the persistent key, and apply the same duplicate-member and proof validation as a JSON request. - Signed metadata and HAIP SD-JWT VC. Requesting Credential Issuer
Metadata with
Accept: application/jwtreturns an ES256 JWT withtyp: openidvci-issuer-metadata+jwt, top-level metadata claims, and a leaf-onlyx5c. The HAIP SD-JWT configuration uses the same persistent certificate-backed signer and assigns each credential a unique OAuth Status List index served as a signedstatuslist+jwt. The OID4VP verifier fetches that list during presentation and checks it with the same issuer key already accepted for the credential. The HAIP SD-JWT configuration’svctis an HTTPS URL on the issuer; that URL serves the matching SD-JWT VC Type Metadata document, while disclosed claims and_sdcommitments use the SD-JWT VC top-level claim model rather than the legacyvccontainer.
These controls are exercised by backend regression tests and by the wallet reference client when HAIP attestation env is configured.
Contract Enforcement
Section titled “Contract Enforcement”- Credential offer envelope enforces XOR: exactly one of
credential_offerorcredential_offer_uri. tx_codeis required when the offer grant includes atx_codeobject.- Proofs are required when proof types are declared for the credential configuration.
- Proof JWT header
typmust beopenid4vci-proof+jwt. - Proof payload must include
aud,nonce, andiat; anonymous clients omitiss. The proof key is carried in exactly one JOSE key-reference header, withjwksupported by this issuer. - Nonce is freshness-bound and one-time in issuance requests (replay and expiry are rejected).
- Deferred polling requires matching
transaction_idand same access token lineage. - Authorization codes and deferred transaction identifiers are redeemed atomically at most once, including under concurrent requests.
- Notification retries are idempotent only for the same event/description; conflicting lifecycle events return a conflict instead of rewriting history.
- Issued SD-JWT VC uses
typ: dc+sd-jwt, canonical tilde serialization, a top-level_sd_alg, and positional recursive disclosure processing for objects and arrays. Reserved/permanent-claim collisions are rejected, and a stored issuer credential must not already contain a Key Binding JWT. mso_mdocverification requires a tagged MSO, version/digest/document/device invariants, unique element identifiers, DeviceResponse version1.0, and an Annex B document-signer profile. Revocation requires external CRL/OCSP state and is not inferred from local certificate-path validation.
Endpoints
Section titled “Endpoints”| Endpoint Role | Discovery Source | Purpose |
|---|---|---|
| Credential Issuer Metadata Endpoint | /.well-known/openid-credential-issuer/{issuer-path} |
Discover issuer metadata, credential configurations, and endpoint URLs |
| Authorization Server Metadata Endpoint | /.well-known/oauth-authorization-server/{issuer-path} (RFC 8414) |
Discover authorization_endpoint, token_endpoint, jwks_uri, and supported grant/auth methods for authorization_code |
| Authorization Server JWKS | jwks_uri from AS metadata (/oid4vci/.well-known/jwks.json) |
Verify JWT/SD-JWT credential signatures (RFC 8414 / RFC 7517) |
| Pushed Authorization Request Endpoint | pushed_authorization_request_endpoint from AS metadata |
Validate and bind a short-lived HAIP authorization request |
| Credential Offer URI | credential_offer_uri |
Retrieve a credential offer by reference |
| Token Endpoint | Issuer/Authorization Server metadata | Exchange pre-authorized_code or authorization_code for an access token; accepts client attestation headers |
| Nonce Endpoint | nonce_endpoint from issuer metadata |
Public endpoint that returns a fresh, single-use c_nonce; no access token is required |
| Credential Endpoint | credential_endpoint from issuer metadata |
Submit proof and request credential issuance |
| Deferred Credential Endpoint | deferred_credential_endpoint from issuer metadata |
Poll a pending issuance transaction with transaction_id |
| Status List Endpoint | Credential status.status_list.uri |
Retrieve the certificate-backed signed OAuth Status List Token |
Illustrative Examples (Non-Normative)
Section titled “Illustrative Examples (Non-Normative)”- Pre-authorized token request body (form-encoded):
grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code&pre-authorized_code=... - Proof JWT protected header for the default mDL
mso_mdoc:{"typ":"openid4vci-proof+jwt","alg":"ES256","jwk":{...}}, where the EC P-256 public key is the device key bound into the MSO. - Deferred credential response shape:
{"transaction_id":"...","c_nonce":"...","c_nonce_expires_in":...}
Default credential format (behavioural change)
Section titled “Default credential format (behavioural change)”As of the parity-then-flip change, the issuer’s default and lead credential configuration is the ISO/IEC 18013-5 mobile driving licence (mso_mdoc, configuration ID MobileDrivingLicenceMsoMdoc). This was previously the SD-JWT VC university-degree configuration.
What changed: a request that omits an explicit credential configuration (an offer with no credential_configuration_ids, or a credential request that relies on the issuer default) now receives the mDL mso_mdoc instead of the SD-JWT VC.
What did not change: explicit format selection behaves exactly as before. SD-JWT VC and the W3C formats remain fully supported and selectable by naming their configuration:
- SD-JWT VC:
credential_configuration_ids: ["UniversityDegreeCredential"] - JWT VC JSON:
credential_configuration_ids: ["UniversityDegreeCredentialJWT"] - JWT VC JSON-LD:
credential_configuration_ids: ["UniversityDegreeCredentialJWTLD"] - LDP VC:
credential_configuration_ids: ["UniversityDegreeCredentialLDP"]
Action for consumers: API consumers that relied on the implicit SD-JWT VC default must now name UniversityDegreeCredential (or the desired configuration) explicitly to continue receiving SD-JWT VC. The wallet harness honours the WALLET_DEFAULT_CREDENTIAL_FORMAT environment variable (default mso_mdoc) for its stored and presented format.
Note that the mDL proof uses an EC P-256 device key signed with ES256: the proof header jwk is bound into the MSO deviceKeyInfo.deviceKey as a COSE_Key, per ISO/IEC 18013-5.
Credential Inspection (Looking Glass)
Section titled “Credential Inspection (Looking Glass)”The Looking Glass credential inspector treats every registered credential format — including mso_mdoc, the default and lead configuration — as a first-class surface; there is no per-format branch in the UI. After the credential endpoint returns an issued credential, the Looking Glass flow calls POST /lookingglass/decode/credential to decode it through the same shared CredentialFormat registry and evidence shape that OID4VP presentation verification already produces, rather than a JWT-only decoder that would treat mso_mdoc’s CBOR encoding as opaque.
The response keeps two things structurally separate, because they must never be rendered as if they were the same claim:
- Evidence - the credential’s own claims (namespace-nested for
mso_mdoc), plus a selective-disclosure summary naming its mechanism (mso_valuedigestsformso_mdoc,sd_jwt_disclosuresfordc+sd-jwt), a committed-element count, and whether that count is exact. Themso_mdocMSOvalueDigestscount is exact — ISO/IEC 18013-5 has no decoy-digest mechanism. An SD-JWT_sddigest count is reported as an upper bound only, because the spec permits decoy digests specifically so a verifier cannot infer the true claim count from it. This replaces an earlier disclosure count that used SD-JWT tilde-counting semantics for every format, which was always zero formso_mdocregardless of how many elements the MSO actually committed to. - Assurance - what has actually been checked, never collapsed into a single validity flag. This endpoint supplies no issuer keys or IACA trust anchors, so
issuer_trustreadsnot_evaluatedfor every format — distinct fromfailed, which means a signature check ran against real trust material and did not succeed. Formso_mdoconly,digests_consistent_with_msoindependently recomputes each disclosedIssuerSignedItem’s digest against the credential’s own MSOvalueDigests. That proves internal consistency between the items and the MSO, not authenticity of the MSO itself — an unauthenticated MSO with matching digests is trivially forgeable.
Both fields are part of the shared, format-agnostic evidence/assurance shape rather than mso_mdoc-specific additions: the same selective-disclosure summary and assurance envelope render for dc+sd-jwt, jwt_vc_json, jwt_vc_json-ld, and ldp_vc, with the fields that do not apply to a given format simply absent rather than zeroed.
What To Validate
Section titled “What To Validate”- Credential offer envelope: exactly one of
credential_offerorcredential_offer_uri - Metadata retrieval: well-known endpoint resolves to issuer metadata and endpoint URLs
- Token exchange:
pre-authorized_codegrant processing andtx_codeenforcement when offered - Proof JWT:
typ=openid4vci-proof+jwt, JOSE-headerjwkkey binding,audmatches issuer,nonceis a live single-usec_nonce - Nonce behavior: replayed or expired
c_nonceis rejected; next nonce is returned after successful issuance - Credential response: serialization matches negotiated format (e.g.
dc+sd-jwtincludes issuer-signed JWT + disclosures,ldp_vcincludes Data Integrity proof,mso_mdocis base64url-encoded CBORIssuerSignedwith a COSE_Sign1IssuerAuth) - Credential time claims (
iat/nbf/exp, and mdoc MSOvalidityInfo) are rounded to the start of the UTC day (RFC 9901 §10.1) so same-dataset credentials are not linkable by precise issuance timestamps - Deferred flow:
issuance_pendingbefore ready time, then final credential on successful poll - Authorization Server metadata:
authorization_endpoint/token_endpointresolve and accept the discoveredauthorization_codegrant - Client attestation (when configured): a request presenting
OAuth-Client-Attestation/-PoPis authenticated by that mechanism, not silently downgraded on failure; replayed PoPjtiis rejected - Key attestation (when a configuration requires it): credential requests without a valid
key_attestationproof header are rejected withinvalid_proof - Encrypted responses (when requested):
credential_response_encryptionis validated against advertisedalg/encvalues and the response is returned as a JWE - Credential inspection:
POST /lookingglass/decode/credentialon an issuedmso_mdocreports a non-zero, exactcommitted_countandissuer_trust: not_evaluated(neverfailed, since no trust anchor was supplied); the same call ondc+sd-jwtreportscommitted_count_is_exact: false