Skip to content

OID4VCI

  • OpenID for Verifiable Credential Issuance 1.0 (final)
  • OAuth 2.0 Authorization Framework (token and grant semantics)
  • SD-JWT VC profile (dc+sd-jwt credential format)
  • W3C Verifiable Credentials Data Model 1.1 / 2.0 (jwt_vc_json, jwt_vc_json-ld, ldp_vc formats)
  • W3C VC Data Integrity 1.0 (ecdsa-rdfc-2019, eddsa-rdfc-2022 cryptosuites for ldp_vc)
Flow IDNameStepsDescription
oid4vci-pre-authorizedPre-Authorized Code6Resolve offer, discover metadata, exchange pre-authorized code, receive token + c_nonce, submit proof, receive issued credential
oid4vci-pre-authorized-tx-codePre-Authorized + tx_code6Same flow with mandatory tx_code at token exchange
oid4vci-deferred-issuanceDeferred Issuance8Full end-to-end flow: offer, metadata, token, credential request, deferred response with transaction_id, polling, credential ready
  • Pre-Authorized Issuance — Resolve by-reference offer, exchange token, submit proof, receive issued credential (format per credential configuration)
  • Pre-Authorized + tx_code — Enforce out-of-band tx_code before token issuance
  • Deferred Issuance Polling — Receive transaction_id, poll until credential is ready
PropertyValue
Credential configuration selectionWallet chooses from credential_configurations_supported (e.g., one configuration describing a university degree VC type)
Credential formatsdc+sd-jwt (SD-JWT VC), jwt_vc_json, jwt_vc_json-ld, ldp_vc (W3C Data Integrity)
Proof containerproof or proofs with proof_type: jwt (e.g., {"proof_type":"jwt","jwt":"<compact-jws>"})
Proof JWT header typeopenid4vci-proof+jwt
Proof JWT required claimsiss, sub, aud, nonce, iat, exp, cnf.jwk
Deferred issuance indicatortransaction_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)”
  1. Resolve Credential Offer — Wallet receives credential_offer_uri out-of-band and fetches the credential offer object from the Credential Issuer. Offer contains credential_issuer, credential_configuration_ids, and grants.urn:ietf:params:oauth:grant-type:pre-authorized_code.
  2. Discover Issuer Metadata — Wallet fetches /.well-known/openid-credential-issuer to discover credential_configurations_supported, credential_endpoint, nonce_endpoint, deferred_credential_endpoint, and token endpoint URL.
  3. Token Request — Wallet calls token endpoint with grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code, pre-authorized_code, and tx_code when required by the offer grant.
  4. Token Response — Authorization Server validates the pre-authorized code (and tx_code if required) and returns access_token, token_type, scope (if applicable), c_nonce, and c_nonce_expires_in.
  5. Credential Request — Wallet submits credential_configuration_id and proof/proofs (proof_type: jwt) with a proof JWT bound to the active c_nonce and the credential issuer audience.
  6. Credential Response — Issuer validates proof key binding, nonce freshness, and audience/subject constraints, then returns:
    • Immediate: format matching the credential configuration (e.g. dc+sd-jwt with disclosures, jwt_vc_json, jwt_vc_json-ld, or ldp_vc with Data Integrity proof), credential, next c_nonce, or
    • Deferred: transaction_id, next c_nonce — wallet then polls deferred_credential endpoint until credential is ready.
  • Credential offer envelope enforces XOR: exactly one of credential_offer or credential_offer_uri.
  • tx_code is required when the offer grant includes a tx_code object.
  • Proofs are required when proof types are declared for the credential configuration.
  • Proof JWT header typ must be openid4vci-proof+jwt.
  • Proof must include iss, sub, aud, nonce, iat, exp, and cnf.jwk.
  • Nonce is freshness-bound and one-time in issuance requests (replay and expiry are rejected).
  • Deferred polling requires matching transaction_id and same access token lineage.
Endpoint RoleDiscovery SourcePurpose
Credential Issuer Metadata Endpoint/.well-known/openid-credential-issuer/{issuer-path}Discover issuer metadata, credential configurations, and endpoint URLs
Credential Offer URIcredential_offer_uriRetrieve a credential offer by reference
Token EndpointIssuer/Authorization Server metadataExchange pre-authorized_code (or authorization grant) for access token and nonce
Nonce Endpointnonce_endpoint from issuer metadataRequest a fresh c_nonce challenge when needed
Credential Endpointcredential_endpoint from issuer metadataSubmit proof and request credential issuance
Deferred Credential Endpointdeferred_credential_endpoint from issuer metadataPoll a pending issuance transaction with transaction_id
  • 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: {"typ":"openid4vci-proof+jwt","alg":"<wallet-signing-alg>"} and payload includes aud, nonce, cnf.jwk
  • Deferred credential response shape: {"transaction_id":"...","c_nonce":"...","c_nonce_expires_in":...}
  • Credential offer envelope: exactly one of credential_offer or credential_offer_uri
  • Metadata retrieval: well-known endpoint resolves to issuer metadata and endpoint URLs
  • Token exchange: pre-authorized_code grant processing and tx_code enforcement when offered
  • Proof JWT: typ=openid4vci-proof+jwt, cnf.jwk key binding, aud matches issuer, nonce matches active c_nonce
  • Nonce behavior: replayed or expired c_nonce is rejected; next nonce is returned after successful issuance
  • Credential response: serialization matches negotiated format (e.g. dc+sd-jwt includes issuer-signed JWT + disclosures, ldp_vc includes Data Integrity proof)
  • Deferred flow: issuance_pending before ready time, then final credential on successful poll