OID4VCI and OID4VP Reference
This page is the technical reference for integrators building issuers or verifiers that interoperate with the ISBE Holder Wallet.
The wallet acts as a client in both protocols. It does not expose any public API of its own; it is the issuers and verifiers who must expose the endpoints described here.
OID4VCI — Credential reception
The wallet implements the pre-authorized flow of OpenID for Verifiable Credential Issuance 1.0.
Endpoints the issuer must expose
| Endpoint | Description |
|---|---|
GET /.well-known/openid-credential-issuer | Issuer metadata. |
POST /token | Token endpoint. Exchanges the pre-authorized_code for an access_token. |
POST /credential | Credential endpoint. Returns the signed credential. |
POST /deferred_credential | (Optional) Deferred credential endpoint. For deferred issuance. |
Issuer metadata (openid-credential-issuer)
The issuer must publish its metadata at /.well-known/openid-credential-issuer. The wallet fetches them when processing the credential_offer.
Minimum required fields:
{
"credential_issuer": "https://issuer.example.redisbe.com",
"credential_endpoint": "https://issuer.example.redisbe.com/credential",
"credentials_supported": [
{
"format": "jwt_vc_json",
"id": "CredentialTypeName",
"types": ["VerifiableCredential", "CredentialTypeName"],
"cryptographic_binding_methods_supported": ["did:key", "did:jwk"],
"cryptographic_suites_supported": ["ES256K", "EdDSA"]
}
]
}
credential_offer structure
The offer can be delivered directly in the QR/deep link or by reference via credential_offer_uri.
By value:
openid-credential-offer://?credential_offer=<URL-encoded JSON>
By reference:
openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.com%2Foffer%2Fabc123
credential_offer object:
{
"credential_issuer": "https://issuer.example.redisbe.com",
"credentials": ["CredentialTypeName"],
"grants": {
"urn:ietf:params:oauth:grant-type:pre-authorized_code": {
"pre-authorized_code": "SplxlOBeZQQYbYS6WxSbIA",
"tx_code": {
"length": 6,
"input_mode": "numeric",
"description": "Enter the code received via SMS"
}
}
}
}
The tx_code field is optional. If the issuer does not require a PIN, omit the field entirely.
Token endpoint
The wallet makes POST /token with the following parameters in the body (form-urlencoded):
| Parameter | Value |
|---|---|
grant_type | urn:ietf:params:oauth:grant-type:pre-authorized_code |
pre-authorized_code | The code from the credential_offer. |
tx_code | (Conditional) The PIN entered by the holder, if the issuer required it. |
Successful response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 86400,
"c_nonce": "tZignsnFbp",
"c_nonce_expires_in": 86400
}
The c_nonce field is optional but required if the issuer demands proof of possession at the /credential endpoint.
Credential endpoint
The wallet makes POST /credential with:
- Header:
Authorization: Bearer <access_token> - JSON body:
{
"format": "jwt_vc_json",
"types": ["VerifiableCredential", "CredentialTypeName"],
"proof": {
"proof_type": "jwt",
"jwt": "<JWT signed with the holder's private key>"
}
}
proof.jwt structure:
The proof of possession JWT is signed by the holder and contains:
{
"alg": "ES256K",
"typ": "openid4vci-proof+jwt",
"kid": "did:key:z6Mk...#z6Mk..."
}
.
{
"iss": "did:key:z6MkszZtxCmA2Ce4vUV132PCuLQmwnaDD5mw2L23fGNnsiRn",
"aud": "https://issuer.example.redisbe.com",
"iat": 1700000000,
"nonce": "tZignsnFbp"
}
The nonce in the proof.jwt must match the c_nonce returned by the token endpoint.
Successful response (immediate issuance):
{
"format": "jwt_vc_json",
"credential": "eyJhbGciOiJFUzI1NiIs..."
}
Response for deferred issuance:
{
"acceptance_token": "eyJhbGciOiJSUzI1NiIs...",
"c_nonce": "wlbQc6pCJp",
"c_nonce_expires_in": 86400
}
Deferred credential endpoint
If the issuer returns an acceptance_token, the wallet will periodically query POST /deferred_credential:
{
"acceptance_token": "eyJhbGciOiJSUzI1NiIs..."
}
While the credential is not ready, the issuer responds with HTTP 202. When it is ready, it returns the credential with HTTP 200 in the same format as the /credential endpoint.
OID4VP — Credential presentation
The wallet implements OpenID for Verifiable Presentations 1.0 with DCQL (Digital Credentials Query Language).
The ISBE wallet uses DCQL for presentation criteria. The presentation_definition object from DIF PEv2 is not supported. Verifiers must use the dcql_query field in the authorization_request.
Presentation flow
Request deep link
By value:
openid4vp://?<URL-encoded authorization_request parameters>
By reference (recommended):
openid4vp://?request_uri=https%3A%2F%2Fverifier.example.com%2Frequest%2Fabc123
authorization_request structure
The verifier can deliver the authorization_request as a URL or as a signed JWT. Required fields:
{
"response_type": "vp_token",
"response_mode": "direct_post",
"response_uri": "https://verifier.example.com/response",
"client_id": "https://verifier.example.com",
"nonce": "n-0S6_WzA2Mj",
"dcql_query": {
"credentials": [
{
"id": "credential_query_id",
"format": "jwt_vc_json",
"claims": [
{"path": ["$.vc.credentialSubject.nombre"]},
{"path": ["$.vc.credentialSubject.fechaNacimiento"]}
]
}
]
}
}
| Field | Description |
|---|---|
response_type | Always vp_token. |
response_mode | Always direct_post. The wallet does not support other modes. |
response_uri | URL where the wallet will send the VP. |
client_id | Verifier identifier. Must match the aud of the VP. |
nonce | Random value to prevent replay attacks. The wallet includes it in the signed VP. |
dcql_query | Credential selection criteria in DCQL format. |
dcql_query structure
The credentials field is an array of objects, each describing a required credential:
{
"credentials": [
{
"id": "credential_query_id",
"format": "jwt_vc_json",
"meta": {
"vct_values": ["CredentialTypeName"]
},
"claims": [
{"path": ["$.vc.credentialSubject.nombre"]},
{"path": ["$.vc.credentialSubject.documentoIdentidad"]}
]
}
]
}
| Field | Description |
|---|---|
id | Query identifier. Referenced in the presentation_submission. |
format | Always jwt_vc_json. |
meta.vct_values | (Optional) Accepted credential types. |
claims | (Optional) Specific required attributes. The wallet checks the credential contains them. |
Wallet response to the verifier
The wallet makes POST <response_uri> with body application/x-www-form-urlencoded:
vp_token=<VP JWT>&presentation_submission=<URL-encoded JSON>
vp_token structure (VP JWT):
// Header
{
"alg": "ES256K",
"typ": "JWT",
"kid": "did:key:z6Mk...#z6Mk..."
}
// Payload
{
"iss": "did:key:z6MkszZtxCmA2Ce4vUV132PCuLQmwnaDD5mw2L23fGNnsiRn",
"aud": "https://verifier.example.com",
"nonce": "n-0S6_WzA2Mj",
"iat": 1700000000,
"exp": 1700003600,
"vp": {
"@context": ["https://www.w3.org/2018/credentials/v1"],
"type": ["VerifiablePresentation"],
"verifiableCredential": [
"eyJhbGciOiJFUzI1NiIs..."
]
}
}
The iss is the holder's DID. The aud is the verifier's client_id.
presentation_submission structure:
{
"id": "random-id",
"definition_id": "dcql_query",
"descriptor_map": [
{
"id": "credential_query_id",
"format": "jwt_vp",
"path": "$",
"path_nested": {
"id": "credential_query_id",
"format": "jwt_vc",
"path": "$.vp.verifiableCredential[0]"
}
}
]
}
Verifier response
After receiving the VP, the verifier must respond with HTTP 200. It can include a redirect_uri in the body to redirect the holder to a continuation URL:
{
"redirect_uri": "https://verifier.example.com/success?session=abc123"
}
If the verifier does not need to redirect, it can respond with HTTP 200 and an empty body.
Supported cryptographic curves
| Curve | JWA identifier | DID method |
|---|---|---|
| secp256k1 | ES256K | did:key (prefix zQ3s), did:jwk |
| Ed25519 | EdDSA | did:key (prefix z6Mk), did:jwk |
The wallet uses the curve configured when creating the account. Issuers and verifiers must declare the cryptographic suites they accept in their metadata (cryptographic_suites_supported).
Reference sources
| Specification | URL |
|---|---|
| OID4VCI 1.0 | https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html |
| OID4VP 1.0 | https://openid.net/specs/openid-4-verifiable-presentations-1_0.html |
| DCQL | https://identity.foundation/credential-query-language/ |
| W3C VC Data Model 2.0 | https://www.w3.org/TR/vc-data-model-2.0/ |