@bedrock/vc-delivery 5.5.0 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/http.js +47 -1
- package/lib/oid4/http.js +6 -0
- package/lib/oid4/oid4vci.js +5 -1
- package/lib/oid4/oid4vp.js +12 -0
- package/package.json +1 -1
package/lib/http.js
CHANGED
|
@@ -16,6 +16,8 @@ import {getWorkflowId} from './helpers.js';
|
|
|
16
16
|
import {logger} from './logger.js';
|
|
17
17
|
import {createValidateMiddleware as validate} from '@bedrock/validation';
|
|
18
18
|
|
|
19
|
+
const {util: {BedrockError}} = bedrock;
|
|
20
|
+
|
|
19
21
|
// FIXME: remove and apply at top-level application
|
|
20
22
|
bedrock.events.on('bedrock-express.configure.bodyParser', app => {
|
|
21
23
|
app.use(bodyParser.json({
|
|
@@ -32,7 +34,8 @@ export async function addRoutes({app, service} = {}) {
|
|
|
32
34
|
const baseUrl = `${routePrefix}/:localId`;
|
|
33
35
|
const routes = {
|
|
34
36
|
exchanges: `${baseUrl}/exchanges`,
|
|
35
|
-
exchange: `${baseUrl}/exchanges/:exchangeId
|
|
37
|
+
exchange: `${baseUrl}/exchanges/:exchangeId`,
|
|
38
|
+
protocols: `${baseUrl}/exchanges/:exchangeId/protocols`
|
|
36
39
|
};
|
|
37
40
|
|
|
38
41
|
// used to retrieve service object (workflow) config
|
|
@@ -117,6 +120,49 @@ export async function addRoutes({app, service} = {}) {
|
|
|
117
120
|
await processExchange({req, res, workflow, exchangeRecord});
|
|
118
121
|
}));
|
|
119
122
|
|
|
123
|
+
// VC-API get interaction `{"protocols": {...}}` options
|
|
124
|
+
app.get(
|
|
125
|
+
routes.protocols,
|
|
126
|
+
cors(),
|
|
127
|
+
getExchange,
|
|
128
|
+
getConfigMiddleware,
|
|
129
|
+
asyncHandler(async (req, res) => {
|
|
130
|
+
if(!req.accepts('json')) {
|
|
131
|
+
// provide hopefully useful error for when VC API interaction URLs
|
|
132
|
+
// are processed improperly, e.g., directly loaded by a browser instead
|
|
133
|
+
// of by a digital wallet
|
|
134
|
+
throw new BedrockError(
|
|
135
|
+
'Unsupported "Accept" header. A VC API interaction URL must be ' +
|
|
136
|
+
'processed by an exchange client, e.g., a digital wallet.', {
|
|
137
|
+
name: 'NotSupportedError',
|
|
138
|
+
details: {httpStatusCode: 406, public: true}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
// construct and return `protocols` object
|
|
142
|
+
const {config: workflow} = req.serviceObject;
|
|
143
|
+
const {exchange} = await req.getExchange();
|
|
144
|
+
const exchangeId = `${workflow.id}/exchanges/${exchange.id}`;
|
|
145
|
+
const protocols = {
|
|
146
|
+
vcapi: exchangeId
|
|
147
|
+
};
|
|
148
|
+
const openIdRoute = `${exchangeId}/openid`;
|
|
149
|
+
if(oid4.supportsOID4VCI({exchange})) {
|
|
150
|
+
// OID4VCI supported; add credential offer URL
|
|
151
|
+
const searchParams = new URLSearchParams();
|
|
152
|
+
const uri = `${openIdRoute}/credential-offer`;
|
|
153
|
+
searchParams.set('credential_offer_uri', uri);
|
|
154
|
+
protocols.OID4VCI = `openid-credential-offer://?${searchParams}`;
|
|
155
|
+
} else if(await oid4.supportsOID4VP({workflow, exchange})) {
|
|
156
|
+
// OID4VP supported; add openid4vp URL
|
|
157
|
+
const searchParams = new URLSearchParams({
|
|
158
|
+
client_id: `${openIdRoute}/client/authorization/response`,
|
|
159
|
+
request_uri: `${openIdRoute}/client/authorization/request`
|
|
160
|
+
});
|
|
161
|
+
protocols.OID4VP = `openid4vp://authorize?${searchParams}`;
|
|
162
|
+
}
|
|
163
|
+
res.json({protocols});
|
|
164
|
+
}));
|
|
165
|
+
|
|
120
166
|
// create OID4* routes to be used with each individual exchange
|
|
121
167
|
await oid4.createRoutes(
|
|
122
168
|
{app, exchangeRoute: routes.exchange, getConfigMiddleware, getExchange});
|
package/lib/oid4/http.js
CHANGED
|
@@ -12,9 +12,14 @@ import {
|
|
|
12
12
|
import {asyncHandler} from '@bedrock/express';
|
|
13
13
|
import bodyParser from 'body-parser';
|
|
14
14
|
import cors from 'cors';
|
|
15
|
+
import {logger} from '../logger.js';
|
|
15
16
|
import {UnsecuredJWT} from 'jose';
|
|
16
17
|
import {createValidateMiddleware as validate} from '@bedrock/validation';
|
|
17
18
|
|
|
19
|
+
// re-export support detection helpers
|
|
20
|
+
export {supportsOID4VCI} from './oid4vci.js';
|
|
21
|
+
export {supportsOID4VP} from './oid4vp.js';
|
|
22
|
+
|
|
18
23
|
/* NOTE: Parts of the OID4VCI design imply tight integration between the
|
|
19
24
|
authorization server and the credential issuance / delivery server. This
|
|
20
25
|
file provides the routes for both and treats them as integrated; supporting
|
|
@@ -374,6 +379,7 @@ export async function createRoutes({
|
|
|
374
379
|
}
|
|
375
380
|
|
|
376
381
|
function _sendOID4Error({res, error}) {
|
|
382
|
+
logger.error(error.message, {error});
|
|
377
383
|
const status = error.details?.httpStatusCode ?? 500;
|
|
378
384
|
const oid4Error = {
|
|
379
385
|
error: _camelToSnakeCase(error.name ?? 'OperationError'),
|
package/lib/oid4/oid4vci.js
CHANGED
|
@@ -149,6 +149,10 @@ export async function processCredentialRequests({req, res, isBatchRequest}) {
|
|
|
149
149
|
return _processExchange({req, res, workflow, exchangeRecord, isBatchRequest});
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
export function supportsOID4VCI({exchange}) {
|
|
153
|
+
return exchange.openId?.expectedCredentialRequests !== undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
152
156
|
function _assertCredentialRequests({
|
|
153
157
|
workflow, credentialRequests, expectedCredentialRequests
|
|
154
158
|
}) {
|
|
@@ -201,7 +205,7 @@ function _assertCredentialRequests({
|
|
|
201
205
|
}
|
|
202
206
|
|
|
203
207
|
function _assertOID4VCISupported({exchange}) {
|
|
204
|
-
if(!exchange
|
|
208
|
+
if(!supportsOID4VCI({exchange})) {
|
|
205
209
|
throw new BedrockError('OID4VCI is not supported by this exchange.', {
|
|
206
210
|
name: 'NotSupportedError',
|
|
207
211
|
details: {httpStatusCode: 400, public: true}
|
package/lib/oid4/oid4vp.js
CHANGED
|
@@ -276,6 +276,18 @@ export async function processAuthorizationResponse({req}) {
|
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
export async function supportsOID4VP({workflow, exchange}) {
|
|
280
|
+
if(!exchange.step) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
let step = workflow.steps[exchange.step];
|
|
284
|
+
if(step.stepTemplate) {
|
|
285
|
+
step = await evaluateTemplate(
|
|
286
|
+
{workflow, exchange, typedTemplate: step.stepTemplate});
|
|
287
|
+
}
|
|
288
|
+
return step.openId !== undefined;
|
|
289
|
+
}
|
|
290
|
+
|
|
279
291
|
function _createClientMetaData() {
|
|
280
292
|
// return default supported `vp_formats`
|
|
281
293
|
return {
|