Skip to content

Commit

Permalink
Support implementations using types from OID4VCI draft examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
dlongley committed Dec 11, 2023
1 parent 3e594c4 commit b3897c1
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 4 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# bedrock-vc-delivery ChangeLog

## 4.3.0 - 2023-12-dd

### Added
- Add support for receiving the `types` property in posted credential
definitions during OID4VCI even if that does not match the served
credential definition in the protocol. The property should likely
be `type` to match the VC data model, but a OID4VCI draft uses
`types` in an example and clients have implemented this.

## 4.2.0 - 2023-11-28

### Added
Expand Down
27 changes: 23 additions & 4 deletions lib/openId.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import {
} from '@bedrock/validation';
import {importJWK, SignJWT} from 'jose';
import {
openIdAuthorizationResponseBody, openIdBatchCredentialBody,
openIdCredentialBody, openIdTokenBody,
openIdAuthorizationResponseBody,
openIdBatchCredentialBody,
openIdCredentialBody,
openIdTokenBody,
presentationSubmission as presentationSubmissionSchema
} from '../schemas/bedrock-vc-exchanger.js';
import {verify, verifyDidProofJwt} from './verify.js';
Expand Down Expand Up @@ -235,7 +237,7 @@ export async function createRoutes({
{
"format": "ldp_vc",
"credential_description": {
"credential_definition": {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
Expand Down Expand Up @@ -289,7 +291,7 @@ export async function createRoutes({
{
credential_requests: [{
"format": "ldp_vc",
"credential_description": {
"credential_definition": {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
Expand Down Expand Up @@ -528,6 +530,11 @@ async function _processCredentialRequests({req, res, isBatchRequest}) {
}
credentialRequests = [req.body];
}

// before asserting, normalize credential requests to use `type` instead of
// `types`; this is to allow for OID4VCI draft 20 implementers that followed
// the non-normative examples
_normalizeCredentialDefinitionTypes({credentialRequests});
_assertCredentialRequests(
{credentialRequests, expectedCredentialRequests});

Expand Down Expand Up @@ -832,3 +839,15 @@ function _validate(validator, data) {
throw result.error;
}
}

function _normalizeCredentialDefinitionTypes({credentialRequests}) {
// normalize credential requests to use `type` instead of `types`
for(const cr of credentialRequests) {
if(cr?.credential_definition?.types) {
if(!cr?.credential_definition?.type) {
cr.credential_definition.type = cr.credential_definition.types;
}
delete cr.credential_definition.types;
}
}
}
8 changes: 8 additions & 0 deletions schemas/bedrock-vc-exchanger.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ const credentialDefinition = {
item: {
type: 'string'
}
},
// allow `types` to be flexible for OID4VCI draft 20 implementers
types: {
type: 'array',
minItems: 2,
item: {
type: 'string'
}
}
}
};
Expand Down
65 changes: 65 additions & 0 deletions test/mocha/30-oid4vci.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,71 @@ describe('exchange w/OID4VCI delivery', () => {
result.credential.id.should.equal(credentialId);
});

it('should pass w/ "types" in credential definition', async () => {
// https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html

/* This flow demonstrates passing an OID4VCI issuance initiation URL
through a CHAPI OID4VCI request. The request is passed to a "Claimed URL"
which was registered on a user's device by a native app. The native app's
domain also published a "manifest.json" file that expressed the same
"Claimed URL" via `credential_handler.url='https://myapp.example/ch'` and
`credential_handler.launchType='redirect'` (TBD). */

// pre-authorized flow, issuer-initiated
const credentialId = `urn:uuid:${uuid()}`;
// generate authorization server key pair
const openIdKeyPair = await helpers.generateKeyPair();
const {openIdUrl: issuanceUrl} = await helpers.createCredentialOffer({
// local target user
userId: 'urn:uuid:01cc3771-7c51-47ab-a3a3-6d34b47ae3c4',
credentialDefinition: mockData.credentialDefinition,
credentialId,
preAuthorized: true,
userPinRequired: false,
capabilityAgent,
exchangerId,
exchangerRootZcap,
openIdKeyPair
});

const chapiRequest = {OID4VC: issuanceUrl};
// CHAPI could potentially be used to deliver the URL to a native app
// that registered a "claimed URL" of `https://myapp.examples/ch`
// like so:
const claimedUrlFromChapi = 'https://myapp.example/ch?request=' +
encodeURIComponent(JSON.stringify(chapiRequest));
const parsedClaimedUrl = new URL(claimedUrlFromChapi);
const parsedChapiRequest = JSON.parse(
parsedClaimedUrl.searchParams.get('request'));
const offer = parseCredentialOfferUrl({url: parsedChapiRequest.OID4VC});

// wallet / client gets access token
const client = await OID4Client.fromCredentialOffer({offer, agent});

// send OID4VCI draft 20 credential definition w/"types" which should
// work with backwards compatibility support
const credentialDefinition = {
...mockData.credentialDefinition,
types: mockData.credentialDefinition.type
};

// wallet / client receives credential
const result = await client.requestCredential({
credentialDefinition,
agent
});
should.exist(result);
result.should.include.keys(['format', 'credential']);
result.format.should.equal('ldp_vc');
// ensure credential subject ID matches static DID
should.exist(result.credential?.credentialSubject?.id);
result.credential.credentialSubject.id.should.equal(
'did:example:ebfeb1f712ebc6f1c276e12ec21');
// ensure VC ID matches
should.exist(result.credential.id);
result.credential.id.should.equal(credentialId);
});

it('should fail when reusing a completed exchange', async () => {
// https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html

Expand Down

0 comments on commit b3897c1

Please sign in to comment.