diff --git a/packages/client/lib/OpenID4VCIClient.ts b/packages/client/lib/OpenID4VCIClient.ts index b7eb6947..f60a5a5b 100644 --- a/packages/client/lib/OpenID4VCIClient.ts +++ b/packages/client/lib/OpenID4VCIClient.ts @@ -42,8 +42,8 @@ import { createAuthorizationRequestUrl } from './AuthorizationCodeClient'; import { createAuthorizationRequestUrlV1_0_11 } from './AuthorizationCodeClientV1_0_11'; import { CredentialOfferClient } from './CredentialOfferClient'; import { CredentialRequestOpts } from './CredentialRequestClient'; -import { CredentialRequestClientBuilderV1_0_13 } from './CredentialRequestClientBuilderV1_0_13'; import { CredentialRequestClientBuilderV1_0_11 } from './CredentialRequestClientBuilderV1_0_11'; +import { CredentialRequestClientBuilderV1_0_13 } from './CredentialRequestClientBuilderV1_0_13'; import { MetadataClient } from './MetadataClient'; import { OpenID4VCIClientStateV1_0_11 } from './OpenID4VCIClientV1_0_11'; import { OpenID4VCIClientStateV1_0_13 } from './OpenID4VCIClientV1_0_13'; @@ -298,7 +298,10 @@ export class OpenID4VCIClient { (kid && clientId && typeof asOpts.clientOpts?.signCallbacks === 'function' ? 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer' : undefined); - if (clientId) { + if (this.isEBSI() || (clientId && kid)) { + if (!clientId) { + throw Error(`Client id expected for EBSI`); + } asOpts.clientOpts = { ...asOpts.clientOpts, clientId, @@ -667,6 +670,9 @@ export class OpenID4VCIClient { } // this.assertIssuerData(); return ( + this.clientId?.includes('ebsi') || + this._state.kid?.includes('did:ebsi:') || + this.getIssuer().includes('ebsi') || this.endpointMetadata.credentialIssuerMetadata?.authorization_endpoint?.includes('ebsi.eu') || this.endpointMetadata.credentialIssuerMetadata?.authorization_server?.includes('ebsi.eu') ); diff --git a/packages/client/lib/OpenID4VCIClientV1_0_11.ts b/packages/client/lib/OpenID4VCIClientV1_0_11.ts index 8438a33a..4bbef186 100644 --- a/packages/client/lib/OpenID4VCIClientV1_0_11.ts +++ b/packages/client/lib/OpenID4VCIClientV1_0_11.ts @@ -297,7 +297,10 @@ export class OpenID4VCIClientV1_0_11 { (kid && clientId && typeof asOpts.clientOpts?.signCallbacks === 'function' ? 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer' : undefined); - if (clientId) { + if (this.isEBSI() || (clientId && kid)) { + if (!clientId) { + throw Error(`Client id expected for EBSI`); + } asOpts.clientOpts = { ...asOpts.clientOpts, clientId, @@ -602,8 +605,8 @@ export class OpenID4VCIClientV1_0_11 { */ public isEBSI() { if ( - (this.credentialOffer?.credential_offer as CredentialOfferPayloadV1_0_11)['credentials'] && - (this.credentialOffer?.credential_offer as CredentialOfferPayloadV1_0_11).credentials.find( + this.credentialOffer && + (this.credentialOffer?.credential_offer as CredentialOfferPayloadV1_0_11)?.credentials?.find( (cred) => // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -612,8 +615,14 @@ export class OpenID4VCIClientV1_0_11 { ) { return true; } - this.assertIssuerData(); - return this.endpointMetadata.credentialIssuerMetadata?.authorization_endpoint?.includes('ebsi.eu') === true; + // this.assertIssuerData(); + return ( + this.clientId?.includes('ebsi') || + this._state.kid?.includes('did:ebsi:') || + this.getIssuer().includes('ebsi') || + this.endpointMetadata.credentialIssuerMetadata?.authorization_endpoint?.includes('ebsi.eu') || + this.endpointMetadata.credentialIssuerMetadata?.authorization_server?.includes('ebsi.eu') + ); } private assertIssuerData(): void { diff --git a/packages/client/lib/OpenID4VCIClientV1_0_13.ts b/packages/client/lib/OpenID4VCIClientV1_0_13.ts index 7f31e1ae..6acec257 100644 --- a/packages/client/lib/OpenID4VCIClientV1_0_13.ts +++ b/packages/client/lib/OpenID4VCIClientV1_0_13.ts @@ -37,8 +37,7 @@ import { CredentialRequestOpts } from './CredentialRequestClient'; import { CredentialRequestClientBuilder } from './CredentialRequestClientBuilder'; import { MetadataClientV1_0_13 } from './MetadataClientV1_0_13'; import { ProofOfPossessionBuilder } from './ProofOfPossessionBuilder'; -import { generateMissingPKCEOpts } from './functions'; -import { sendNotification } from './functions'; +import { generateMissingPKCEOpts, sendNotification } from './functions'; const debug = Debug('sphereon:oid4vci'); @@ -288,7 +287,10 @@ export class OpenID4VCIClientV1_0_13 { (kid && clientId && typeof asOpts.clientOpts?.signCallbacks === 'function' ? 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer' : undefined); - if (clientId) { + if (this.isEBSI() || (clientId && kid)) { + if (!clientId) { + throw Error(`Client id expected for EBSI`); + } asOpts.clientOpts = { ...asOpts.clientOpts, clientId, @@ -654,8 +656,13 @@ export class OpenID4VCIClientV1_0_13 { } } - this.assertIssuerData(); - return this.endpointMetadata.credentialIssuerMetadata?.authorization_endpoint?.includes('ebsi.eu') ?? false; + return ( + this.clientId?.includes('ebsi') || + this._state.kid?.includes('did:ebsi:') || + this.getIssuer().includes('ebsi') || + this.endpointMetadata.credentialIssuerMetadata?.authorization_endpoint?.includes('ebsi.eu') || + this.endpointMetadata.credentialIssuerMetadata?.authorization_server?.includes('ebsi.eu') + ); } private assertIssuerData(): void { diff --git a/packages/client/lib/__tests__/ProofOfPossessionBuilder.spec.ts b/packages/client/lib/__tests__/ProofOfPossessionBuilder.spec.ts index 54693daf..0c57e951 100644 --- a/packages/client/lib/__tests__/ProofOfPossessionBuilder.spec.ts +++ b/packages/client/lib/__tests__/ProofOfPossessionBuilder.spec.ts @@ -62,10 +62,10 @@ describe('ProofOfPossession Builder ', () => { it('should fail without supplied proof or callbacks and with kid without did', async function () { await expect( ProofOfPossessionBuilder.fromProof(undefined as never, OpenId4VCIVersion.VER_1_0_13) - .withIssuer(IDENTIPROOF_ISSUER_URL) - .withClientId('sphereon:wallet') - .withKid(kid_withoutDid) - .build(), + .withIssuer(IDENTIPROOF_ISSUER_URL) + .withClientId('sphereon:wallet') + .withKid(kid_withoutDid) + .build(), ).rejects.toThrow(Error(PROOF_CANT_BE_CONSTRUCTED)); }); @@ -87,11 +87,11 @@ describe('ProofOfPossession Builder ', () => { callbacks: { signCallback: proofOfPossessionCallbackFunction }, version: OpenId4VCIVersion.VER_1_0_08, }) - .withJwt(undefined as never) - .withIssuer(IDENTIPROOF_ISSUER_URL) - .withClientId('sphereon:wallet') - .withKid(kid_withoutDid) - .build(), + .withJwt(undefined as never) + .withIssuer(IDENTIPROOF_ISSUER_URL) + .withClientId('sphereon:wallet') + .withKid(kid_withoutDid) + .build(), ).toThrow(Error(NO_JWT_PROVIDED)); }); @@ -118,10 +118,10 @@ describe('ProofOfPossession Builder ', () => { }, version: OpenId4VCIVersion.VER_1_0_08, }) - .withIssuer(IDENTIPROOF_ISSUER_URL) - .withKid(kid_withoutDid) - .withClientId('sphereon:wallet') - .build(); + .withIssuer(IDENTIPROOF_ISSUER_URL) + .withKid(kid_withoutDid) + .withClientId('sphereon:wallet') + .build(); expect(proof).toBeDefined(); }); @@ -152,10 +152,10 @@ describe('ProofOfPossession Builder ', () => { callbacks: { signCallback: proofOfPossessionCallbackFunction }, version: OpenId4VCIVersion.VER_1_0_08, }) - .withIssuer(IDENTIPROOF_ISSUER_URL) - .withClientId('sphereon:wallet') - .withKid(kid_withoutDid) - .build(), + .withIssuer(IDENTIPROOF_ISSUER_URL) + .withClientId('sphereon:wallet') + .withKid(kid_withoutDid) + .build(), ).rejects.toThrow(Error(JWS_NOT_VALID)); }); @@ -186,10 +186,10 @@ describe('ProofOfPossession Builder ', () => { callbacks: { signCallback: proofOfPossessionCallbackFunction }, version: OpenId4VCIVersion.VER_1_0_08, }) - .withIssuer(IDENTIPROOF_ISSUER_URL) - .withClientId('sphereon:wallet') - .withKid(kid_withoutDid) - .build(), + .withIssuer(IDENTIPROOF_ISSUER_URL) + .withClientId('sphereon:wallet') + .withKid(kid_withoutDid) + .build(), ).rejects.toThrow(Error(JWS_NOT_VALID)); }); }); diff --git a/packages/client/lib/__tests__/SdJwt.spec.ts b/packages/client/lib/__tests__/SdJwt.spec.ts index aa137210..a699988b 100644 --- a/packages/client/lib/__tests__/SdJwt.spec.ts +++ b/packages/client/lib/__tests__/SdJwt.spec.ts @@ -215,37 +215,37 @@ describe('sd-jwt vc', () => { const offered = supported['SdJwtCredentialId'] as CredentialSupportedSdJwtVc; nock(issuerMetadata.token_endpoint as string) - .post('/') - .reply(200, async (_, body: string) => { - const parsedBody = Object.fromEntries(body.split('&').map((x) => x.split('='))); - return createAccessTokenResponse(parsedBody as AccessTokenRequest, { - credentialOfferSessions: vcIssuer.credentialOfferSessions, - accessTokenIssuer: 'https://issuer.example.com', - cNonces: vcIssuer.cNonces, - cNonce: 'a-c-nonce', - accessTokenSignerCallback: async () => 'ey.val.ue', - tokenExpiresIn: 500, + .post('/') + .reply(200, async (_, body: string) => { + const parsedBody = Object.fromEntries(body.split('&').map((x) => x.split('='))); + return createAccessTokenResponse(parsedBody as AccessTokenRequest, { + credentialOfferSessions: vcIssuer.credentialOfferSessions, + accessTokenIssuer: 'https://issuer.example.com', + cNonces: vcIssuer.cNonces, + cNonce: 'a-c-nonce', + accessTokenSignerCallback: async () => 'ey.val.ue', + tokenExpiresIn: 500, + }); }); - }); await client.acquireAccessToken({ pin: '123' }); nock(issuerMetadata.credential_endpoint as string) - .post('/') - .reply(200, async (_, body) => - vcIssuer.issueCredential({ - credentialRequest: { ...(body as CredentialRequestV1_0_13), credential_identifier: offered.vct }, - credential: { - vct: 'Hello', - iss: 'example.com', - iat: 123, - // Defines what can be disclosed (optional) - __disclosureFrame: { - name: true, + .post('/') + .reply(200, async (_, body) => + vcIssuer.issueCredential({ + credentialRequest: { ...(body as CredentialRequestV1_0_13), credential_identifier: offered.vct }, + credential: { + vct: 'Hello', + iss: 'example.com', + iat: 123, + // Defines what can be disclosed (optional) + __disclosureFrame: { + name: true, + }, }, - }, - newCNonce: 'new-c-nonce', - }), - ); + newCNonce: 'new-c-nonce', + }), + ); const credentials = await client.acquireCredentials({ credentialIdentifier: offered.vct, diff --git a/packages/issuer/lib/__tests__/VcIssuerBuilder.spec.ts b/packages/issuer/lib/__tests__/VcIssuerBuilder.spec.ts index 34b4c298..5ce36bff 100644 --- a/packages/issuer/lib/__tests__/VcIssuerBuilder.spec.ts +++ b/packages/issuer/lib/__tests__/VcIssuerBuilder.spec.ts @@ -208,5 +208,4 @@ describe('VcIssuer builder should', () => { credentialOffer: { credential_offer: { credentials: ['test_credential'], credential_issuer: 'test_issuer' } }, }) }) - })