Skip to content

Commit a7127d8

Browse files
committed
Start adding support for di_vp DID proof type during OID4VCI.
1 parent 81acb0a commit a7127d8

5 files changed

Lines changed: 105 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# @digitalbazaar/oid4-client Changelog
22

3+
## 5.12.0 - 2026-mm-dd
4+
5+
### Added
6+
- Add support for `di_vp` DID proof type during OID4VCI.
7+
38
## 5.11.0 - 2026-05-01
49

510
### Added

lib/OID4Client.js

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import {
55
createAuthorizationDetailsFromOffer, createCredentialRequestsFromOffer
66
} from './oid4vci/credentialOffer.js';
7+
import {generateDIDProofDIVP, generateDIDProofJWT} from './oid4vci/proofs.js';
78
import {createNamedError} from './util.js';
8-
import {generateDIDProofJWT} from './oid4vci/proofs.js';
99
import {httpClient} from '@digitalbazaar/http-client';
1010
import {robustDiscoverIssuer} from './oid4vci/discovery.js';
1111

@@ -231,6 +231,46 @@ export class OID4Client {
231231
}
232232
}
233233

234+
async function _addDIDProof({
235+
issuerConfig, json, nonce, did, didProofSigner
236+
}) {
237+
// FIXME: allow these to combine; and choose just one based on
238+
// `proof_types_supported`, defaulting to `jwt` if nothing is specified
239+
await _addDIDProofDIVP({issuerConfig, json, nonce, did, didProofSigner});
240+
// add DID proof `jwt` to json
241+
await _addDIDProofJWT({issuerConfig, json, nonce, did, didProofSigner});
242+
}
243+
244+
async function _addDIDProofDIVP({
245+
issuerConfig, json, nonce, did, didProofSigner
246+
}) {
247+
// generate a DID proof DI VP
248+
const {issuer: domain} = issuerConfig;
249+
const di_vp = [await generateDIDProofDIVP({
250+
did,
251+
signer: didProofSigner,
252+
domain,
253+
challenge: nonce
254+
})];
255+
256+
// add proof to body to be posted and loop to retry
257+
const proof = {proof_type: 'di_vp', di_vp};
258+
if(json.credential_requests) {
259+
// OID4VCI Draft 13 only
260+
json.credential_requests = json.credential_requests.map(
261+
cr => ({...cr, proof}));
262+
} else if(json.credential_definition) {
263+
// OID4VCI Draft 13 only
264+
json.proof = proof;
265+
} else {
266+
// OID4VCI 1.0+
267+
json.proofs = {
268+
...proof,
269+
di_vp: [proof.di_vp]
270+
};
271+
}
272+
}
273+
234274
async function _addDIDProofJWT({
235275
issuerConfig, json, nonce, did, didProofSigner
236276
}) {
@@ -278,6 +318,12 @@ async function _requestCredential({
278318
"format": "ldp_vc",
279319
"credential_definition": {...},
280320
// only present on retry after server requests it or if nonce is given
321+
// v1.0 format:
322+
"proofs": {
323+
"di_vp": [VP1, VP2, ...],
324+
"jwt": [JWT1, JWT2, ...]
325+
}
326+
// draft 13 format:
281327
"proof": {
282328
"proof_type": "jwt",
283329
"jwt": "eyJraW..."
@@ -306,6 +352,12 @@ async function _requestCredential({
306352
"format": "ldp_vc",
307353
"credential_definition": {...},
308354
// only present on retry after server requests it
355+
// v1.0 format:
356+
"proofs": {
357+
"di_vp": [VP1, VP2, ...],
358+
"jwt": [JWT1, JWT2, ...]
359+
}
360+
// draft 13 format:
309361
"proof": {
310362
"proof_type": "jwt",
311363
"jwt": "eyJraW..."
@@ -320,8 +372,8 @@ async function _requestCredential({
320372
321373
*/
322374
if(nonce !== undefined) {
323-
// add DID proof JWT to json
324-
await _addDIDProofJWT({issuerConfig, json, nonce, did, didProofSigner});
375+
// add DID proof to json
376+
await _addDIDProof({issuerConfig, json, nonce, did, didProofSigner});
325377
}
326378

327379
let result;
@@ -373,10 +425,8 @@ async function _requestCredential({
373425
({nonce} = await this.getNonce({agent}));
374426
}
375427

376-
// add DID proof JWT to json
377-
await _addDIDProofJWT({
378-
issuerConfig, json, nonce, did, didProofSigner
379-
});
428+
// add DID proof to json
429+
await _addDIDProof({issuerConfig, json, nonce, did, didProofSigner});
380430
}
381431
}
382432

lib/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* Copyright (c) 2022-2026 Digital Bazaar, Inc. All rights reserved.
2+
* Copyright (c) 2022-2026 Digital Bazaar, Inc.
33
*/
44
export * as oid4vp from './oid4vp/index.js';
55
export * as query from './query/index.js';
@@ -15,5 +15,5 @@ export {
1515
signJWT,
1616
selectJwk
1717
} from './util.js';
18-
export {generateDIDProofJWT} from './oid4vci/proofs.js';
18+
export {generateDIDProofDIVP, generateDIDProofJWT} from './oid4vci/proofs.js';
1919
export {OID4Client} from './OID4Client.js';

lib/oid4vci/proofs.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
11
/*!
2-
* Copyright (c) 2022-2025 Digital Bazaar, Inc. All rights reserved.
2+
* Copyright (c) 2022-2026 Digital Bazaar, Inc.
33
*/
4+
import {createPresentation, signPresentation} from '@digitalbazaar/vc';
5+
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
6+
import {cryptosuite as ecdsaRdfc2019CryptoSuite} from
7+
'@digitalbazaar/ecdsa-rdfc-2019-cryptosuite';
8+
import {cryptosuite as eddsaRdfc2022CryptoSuite} from
9+
'@digitalbazaar/eddsa-rdfc-2022-cryptosuite';
410
import {signJWT} from '../util.js';
511

12+
export async function generateDIDProofDIVP({
13+
did, signer, challenge, domain
14+
} = {}) {
15+
const {id} = signer;
16+
const holder = did ?? id?.includes('#') ? id.slice(0, id.indexOf('#')) : id;
17+
const presentation = createPresentation({holder});
18+
return signPresentation({
19+
presentation,
20+
suite: _createDataIntegrityProof({signer}),
21+
domain,
22+
challenge
23+
});
24+
}
25+
626
export async function generateDIDProofJWT({
727
signer, nonce, iss, aud, exp, nbf
828
} = {}) {
@@ -36,6 +56,22 @@ export async function generateDIDProofJWT({
3656
return signJWT({payload, protectedHeader, signer});
3757
}
3858

59+
function _createDataIntegrityProof({signer}) {
60+
const {algorithm} = signer;
61+
62+
let cryptosuite;
63+
if(algorithm === 'Ed25519' || algorithm === 'EdDSA') {
64+
cryptosuite = eddsaRdfc2022CryptoSuite;
65+
} else if(algorithm?.startsWith('P-')) {
66+
cryptosuite = ecdsaRdfc2019CryptoSuite;
67+
} else {
68+
// default
69+
cryptosuite = eddsaRdfc2022CryptoSuite;
70+
}
71+
72+
return new DataIntegrityProof({signer, cryptosuite});
73+
}
74+
3975
function _curveToAlg(crv) {
4076
if(crv === 'Ed25519' || crv === 'Ed448') {
4177
return 'EdDSA';

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323
"lib/**/*.js"
2424
],
2525
"dependencies": {
26+
"@digitalbazaar/data-integrity": "^2.5.0",
27+
"@digitalbazaar/ecdsa-rdfc-2019-cryptosuite": "^1.3.0",
28+
"@digitalbazaar/eddsa-rdfc-2022-cryptosuite": "^1.3.0",
2629
"@digitalbazaar/http-client": "^4.0.0",
30+
"@digitalbazaar/vc": "^7.3.0",
2731
"@hpke/core": "^1.7.5",
2832
"base64url-universal": "^2.0.0",
2933
"cborg": "^4.5.8",

0 commit comments

Comments
 (0)