Saltar al contenido principal

Referencia OID4VCI y OID4VP

Esta página es la referencia técnica para integradores que construyen emisores (issuers) o verificadores (verifiers) que interoperan con la ISBE Holder Wallet.

La wallet actúa como cliente en ambos protocolos. No expone ninguna API pública propia; son los emisores y verificadores quienes deben exponer los endpoints descritos aquí.


OID4VCI — Recepción de credenciales

La wallet implementa el flujo pre-autorizado de OpenID for Verifiable Credential Issuance 1.0.

Endpoints que debe exponer el emisor

EndpointDescripción
GET /.well-known/openid-credential-issuerMetadatos del emisor (Issuer Metadata).
POST /tokenToken endpoint. Intercambia el pre-authorized_code por un access_token.
POST /credentialCredential endpoint. Devuelve la credencial firmada.
POST /deferred_credential(Opcional) Deferred credential endpoint. Para emisión diferida.

Metadatos del emisor (openid-credential-issuer)

El emisor debe publicar sus metadatos en /.well-known/openid-credential-issuer. La wallet los obtiene al procesar la credential_offer.

Campos mínimos requeridos:

{
"credential_issuer": "https://issuer.ejemplo.redisbe.com",
"credential_endpoint": "https://issuer.ejemplo.redisbe.com/credential",
"credentials_supported": [
{
"format": "jwt_vc_json",
"id": "NombreDelTipoDeCredencial",
"types": ["VerifiableCredential", "NombreDelTipoDeCredencial"],
"cryptographic_binding_methods_supported": ["did:key", "did:jwk"],
"cryptographic_suites_supported": ["ES256K", "EdDSA"]
}
]
}

Estructura del credential_offer

La oferta puede entregarse directamente en el QR/deep link o por referencia mediante credential_offer_uri.

Por valor:

openid-credential-offer://?credential_offer=<URL-encoded JSON>

Por referencia:

openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.ejemplo.com%2Foffer%2Fabc123

Objeto credential_offer:

{
"credential_issuer": "https://issuer.ejemplo.redisbe.com",
"credentials": ["NombreDelTipoDeCredencial"],
"grants": {
"urn:ietf:params:oauth:grant-type:pre-authorized_code": {
"pre-authorized_code": "SplxlOBeZQQYbYS6WxSbIA",
"tx_code": {
"length": 6,
"input_mode": "numeric",
"description": "Introduce el código recibido por SMS"
}
}
}
}

El campo tx_code es opcional. Si el emisor no requiere PIN, omite el campo completo.

Token endpoint

La wallet hace POST /token con los siguientes parámetros en el body (form-urlencoded):

ParámetroValor
grant_typeurn:ietf:params:oauth:grant-type:pre-authorized_code
pre-authorized_codeEl código del credential_offer.
tx_code(Condicional) El PIN introducido por el holder, si el emisor lo requirió.

Respuesta exitosa:

{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 86400,
"c_nonce": "tZignsnFbp",
"c_nonce_expires_in": 86400
}

El campo c_nonce es opcional pero requerido si el emisor exige prueba de posesión en el endpoint /credential.

Credential endpoint

La wallet hace POST /credential con:

  • Header: Authorization: Bearer <access_token>
  • Body JSON:
{
"format": "jwt_vc_json",
"types": ["VerifiableCredential", "NombreDelTipoDeCredencial"],
"proof": {
"proof_type": "jwt",
"jwt": "<JWT firmado con la clave privada del holder>"
}
}

Estructura del proof.jwt:

El JWT de prueba de posesión es firmado por el holder y contiene:

{
"alg": "ES256K",
"typ": "openid4vci-proof+jwt",
"kid": "did:key:z6Mk...#z6Mk..."
}
.
{
"iss": "did:key:z6MkszZtxCmA2Ce4vUV132PCuLQmwnaDD5mw2L23fGNnsiRn",
"aud": "https://issuer.ejemplo.redisbe.com",
"iat": 1700000000,
"nonce": "tZignsnFbp"
}

El nonce en el proof.jwt debe coincidir con el c_nonce devuelto por el token endpoint.

Respuesta exitosa (emisión inmediata):

{
"format": "jwt_vc_json",
"credential": "eyJhbGciOiJFUzI1NiIs..."
}

Respuesta para emisión diferida:

{
"acceptance_token": "eyJhbGciOiJSUzI1NiIs...",
"c_nonce": "wlbQc6pCJp",
"c_nonce_expires_in": 86400
}

Deferred credential endpoint

Si el emisor devuelve un acceptance_token, la wallet consultará periódicamente POST /deferred_credential:

{
"acceptance_token": "eyJhbGciOiJSUzI1NiIs..."
}

Mientras la credencial no esté lista, el emisor responde con HTTP 202. Cuando está lista, devuelve la credencial con HTTP 200 en el mismo formato que el endpoint /credential.


OID4VP — Presentación de credenciales

La wallet implementa OpenID for Verifiable Presentations 1.0 con DCQL (Digital Credentials Query Language).

Solo DCQL — no DIF Presentation Exchange

La wallet ISBE usa DCQL para los criterios de presentación. El objeto presentation_definition de DIF PEv2 no está soportado. Los verificadores deben usar el campo dcql_query en el authorization_request.

Flujo de presentación

Por valor:

openid4vp://?<parámetros URL-encoded del authorization_request>

Por referencia (recomendado):

openid4vp://?request_uri=https%3A%2F%2Fverifier.ejemplo.com%2Frequest%2Fabc123

Estructura del authorization_request

El verificador puede entregar el authorization_request como URL o como JWT firmado. Campos requeridos:

{
"response_type": "vp_token",
"response_mode": "direct_post",
"response_uri": "https://verifier.ejemplo.com/response",
"client_id": "https://verifier.ejemplo.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"]}
]
}
]
}
}
CampoDescripción
response_typeSiempre vp_token.
response_modeSiempre direct_post. La wallet no soporta otros modos.
response_uriURL donde la wallet enviará la VP.
client_idIdentificador del verificador. Debe coincidir con el aud de la VP.
nonceValor aleatorio para prevenir ataques de replay. La wallet lo incluye en la VP firmada.
dcql_queryCriterios de selección de credenciales en formato DCQL.

Estructura del dcql_query

El campo credentials es un array de objetos, cada uno describiendo una credencial requerida:

{
"credentials": [
{
"id": "credential_query_id",
"format": "jwt_vc_json",
"meta": {
"vct_values": ["NombreDelTipoDeCredencial"]
},
"claims": [
{"path": ["$.vc.credentialSubject.nombre"]},
{"path": ["$.vc.credentialSubject.documentoIdentidad"]}
]
}
]
}
CampoDescripción
idIdentificador de la query. Se referencia en el presentation_submission.
formatSiempre jwt_vc_json.
meta.vct_values(Opcional) Tipos de credencial aceptados.
claims(Opcional) Atributos específicos requeridos. La wallet verifica que la credencial los contiene.

Respuesta de la wallet al verificador

La wallet hace POST <response_uri> con body application/x-www-form-urlencoded:

vp_token=<JWT de la VP>&presentation_submission=<JSON URL-encoded>

Estructura del vp_token (VP JWT):

// Header
{
"alg": "ES256K",
"typ": "JWT",
"kid": "did:key:z6Mk...#z6Mk..."
}
// Payload
{
"iss": "did:key:z6MkszZtxCmA2Ce4vUV132PCuLQmwnaDD5mw2L23fGNnsiRn",
"aud": "https://verifier.ejemplo.com",
"nonce": "n-0S6_WzA2Mj",
"iat": 1700000000,
"exp": 1700003600,
"vp": {
"@context": ["https://www.w3.org/2018/credentials/v1"],
"type": ["VerifiablePresentation"],
"verifiableCredential": [
"eyJhbGciOiJFUzI1NiIs..."
]
}
}

El iss es el DID del holder. El aud es el client_id del verificador.

Estructura del presentation_submission:

{
"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]"
}
}
]
}

Respuesta del verificador

Tras recibir la VP, el verificador debe responder con HTTP 200. Puede incluir un redirect_uri en el body para redirigir al holder a una URL de continuación:

{
"redirect_uri": "https://verifier.ejemplo.com/success?session=abc123"
}

Si el verificador no necesita redirigir, puede responder con HTTP 200 y body vacío.


Curvas criptográficas soportadas

CurvaIdentificador JWAMétodo DID
secp256k1ES256Kdid:key (prefijo zQ3s), did:jwk
Ed25519EdDSAdid:key (prefijo z6Mk), did:jwk

La wallet usa la curva configurada al crear la cuenta. Los emisores y verificadores deben declarar en sus metadatos las suites criptográficas que aceptan (cryptographic_suites_supported).


Fuentes de referencia

EspecificaciónURL
OID4VCI 1.0https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html
OID4VP 1.0https://openid.net/specs/openid-4-verifiable-presentations-1_0.html
DCQLhttps://identity.foundation/credential-query-language/
W3C VC Data Model 2.0https://www.w3.org/TR/vc-data-model-2.0/