diff --git a/packages/issuer-rest/lib/oid4vci-api-functions.ts b/packages/issuer-rest/lib/oid4vci-api-functions.ts index ac696f7f..001c4e7c 100644 --- a/packages/issuer-rest/lib/oid4vci-api-functions.ts +++ b/packages/issuer-rest/lib/oid4vci-api-functions.ts @@ -1,18 +1,16 @@ import { ACCESS_TOKEN_ISSUER_REQUIRED_ERROR, - AuthorizationRequest, CredentialOfferRESTRequestV1_0_11, - CredentialRequestV1_0_11, - determineGrantTypes, + AuthorizationRequest, CredentialOfferRESTRequest, CredentialRequestV1_0_11, + determineGrantTypes, determineSpecVersionFromOffer, getNumberOrUndefined, Grant, IssueStatusResponse, - JWT_SIGNER_CALLBACK_REQUIRED_ERROR, + JWT_SIGNER_CALLBACK_REQUIRED_ERROR, OpenId4VCIVersion, TokenErrorResponse } from '@sphereon/oid4vci-common'; import { adjustUrl, trimBoth, trimEnd, trimStart } from '@sphereon/oid4vci-common/dist/functions/HttpUtils' import { ITokenEndpointOpts, VcIssuer } from '@sphereon/oid4vci-issuer' import { env, ISingleEndpointOpts, sendErrorResponse } from '@sphereon/ssi-express-support' -import { CredentialFormat } from '@sphereon/ssi-types' import { NextFunction, Request, Response, Router } from 'express' import { v4 as uuidv4 } from 'uuid' @@ -193,16 +191,21 @@ export function createCredentialOfferEndpoint( ) { const path = determinePath(opts?.baseUrl, opts?.path ?? '/webapp/credential-offers', { stripBasePath: true }) console.log(`[OID4VCI] createCredentialOffer endpoint enabled at ${path}`) - router.post(path, async (request: Request, response: Response) => { + router.post(path, async (request: Request, response: Response) => { try { + const specVersion = determineSpecVersionFromOffer(request.body.original_credential_offer) + if(specVersion < OpenId4VCIVersion.VER_1_0_13) { + return sendErrorResponse(response, 400, { error: TokenErrorResponse.invalid_client, error_description: 'credential offer request should be of version 1.0.13 or above' }) + } + const grantTypes = determineGrantTypes(request.body) if (grantTypes.length === 0) { return sendErrorResponse(response, 400, { error: TokenErrorResponse.invalid_grant, error_description: 'No grant type supplied' }) } const grants = request.body.grants as Grant - const credentialIds = request.body.credentials as (string | CredentialFormat)[] - if (!credentialIds || credentialIds.length === 0) { - return sendErrorResponse(response, 400, { error: TokenErrorResponse.invalid_request, error_description: 'No credential ids supplied' }) + const credentialConfigIds = request.body.credential_configuration_ids as string [] + if (!credentialConfigIds || credentialConfigIds.length === 0) { + return sendErrorResponse(response, 400, { error: TokenErrorResponse.invalid_request, error_description: 'credential_configuration_ids missing credential_configuration_ids in credential offer payload' }) } const qrCodeOpts = request.body.qrCodeOpts ?? opts?.qrCodeOpts const result = await issuer.createCredentialOfferURI({ ...request.body, qrCodeOpts, grants }) diff --git a/packages/issuer/lib/VcIssuer.ts b/packages/issuer/lib/VcIssuer.ts index 6b828bc1..1ee4a28a 100644 --- a/packages/issuer/lib/VcIssuer.ts +++ b/packages/issuer/lib/VcIssuer.ts @@ -88,7 +88,7 @@ export class VcIssuer { public async createCredentialOfferURI(opts: { grants?: Grant - credentials?: Array + credential_configuration_ids?: Array credentialDefinition?: JsonLdIssuerCredentialDefinition credentialOfferUri?: string credentialDataSupplierInput?: CredentialDataSupplierInput // Optional storage that can help the credential Data Supplier. For instance to store credential input data during offer creation, if no additional data can be supplied later on @@ -99,14 +99,14 @@ export class VcIssuer { }): Promise { let preAuthorizedCode: string | undefined = undefined let issuerState: string | undefined = undefined - const { grants, credentials } = opts + const { grants, credential_configuration_ids } = opts if (!grants?.authorization_code && !grants?.['urn:ietf:params:oauth:grant-type:pre-authorized_code']) { throw Error(`No grant issuer state or pre-authorized code could be deduced`) } const credentialOfferPayload: CredentialOfferPayloadV1_0_13 = { ...(grants && { grants }), - ...(credentials && { credential_configuration_ids: credentials ?? [] }), + ...(credential_configuration_ids && { credential_configuration_ids: credential_configuration_ids ?? [] }), credential_issuer: this.issuerMetadata.credential_issuer, } as CredentialOfferPayloadV1_0_13 if (grants?.authorization_code) {