diff --git a/packages/callback-example/CHANGELOG.md b/packages/callback-example/CHANGELOG.md index 560d36af..7c120756 100644 --- a/packages/callback-example/CHANGELOG.md +++ b/packages/callback-example/CHANGELOG.md @@ -7,28 +7,15 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @sphereon/oid4vci-callback-example - - - - ## [0.7.2](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.1...v0.7.2) (2023-09-28) **Note:** Version bump only for package @sphereon/oid4vci-callback-example - - - - ## [0.7.1](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.0...v0.7.1) (2023-09-28) - ### Bug Fixes -* Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) - - - - +- Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) # [0.7.0](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.6.0...v0.7.0) (2023-08-19) diff --git a/packages/client/CHANGELOG.md b/packages/client/CHANGELOG.md index a8623855..ce123930 100644 --- a/packages/client/CHANGELOG.md +++ b/packages/client/CHANGELOG.md @@ -7,34 +7,20 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @sphereon/oid4vci-client - - - - ## [0.7.2](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.1...v0.7.2) (2023-09-28) - ### Bug Fixes -* id lookup against server metadata not working ([592ec4b](https://github.com/Sphereon-Opensource/OID4VCI/commit/592ec4b837898eb3022d19479d79b6065e7a0d9e)) - - - - +- id lookup against server metadata not working ([592ec4b](https://github.com/Sphereon-Opensource/OID4VCI/commit/592ec4b837898eb3022d19479d79b6065e7a0d9e)) ## [0.7.1](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.0...v0.7.1) (2023-09-28) - ### Bug Fixes -* Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) -* clearinterval ([214e3c6](https://github.com/Sphereon-Opensource/OID4VCI/commit/214e3c6d7ced9b27c50186db8ed876330230a6a5)) -* relax auth_endpoint handling. Doesn't have to be available when doing pre-auth flow. Client handles errors anyway in case of auth/par flow ([ce39958](https://github.com/Sphereon-Opensource/OID4VCI/commit/ce39958f21f82243f26111fd14bd2443517eef9c)) -* relax auth_endpoint handling. Doesn't have to be available when doing pre-auth flow. Client handles errors anyway in case of auth/par flow ([cb5f9c1](https://github.com/Sphereon-Opensource/OID4VCI/commit/cb5f9c1c12285508c6d403814d032e8883a59e7d)) - - - - +- Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) +- clearinterval ([214e3c6](https://github.com/Sphereon-Opensource/OID4VCI/commit/214e3c6d7ced9b27c50186db8ed876330230a6a5)) +- relax auth_endpoint handling. Doesn't have to be available when doing pre-auth flow. Client handles errors anyway in case of auth/par flow ([ce39958](https://github.com/Sphereon-Opensource/OID4VCI/commit/ce39958f21f82243f26111fd14bd2443517eef9c)) +- relax auth_endpoint handling. Doesn't have to be available when doing pre-auth flow. Client handles errors anyway in case of auth/par flow ([cb5f9c1](https://github.com/Sphereon-Opensource/OID4VCI/commit/cb5f9c1c12285508c6d403814d032e8883a59e7d)) # [0.7.0](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.6.0...v0.7.0) (2023-08-19) diff --git a/packages/client/README.md b/packages/client/README.md index ff28f488..b1da2a32 100644 --- a/packages/client/README.md +++ b/packages/client/README.md @@ -57,7 +57,6 @@ import { OpenID4VCIClient } from '@sphereon/oid4vci-client'; // The client is initiated from a URI. This URI is provided by the Issuer, typically as a URL or QR code. const client = await OpenID4VCIClient.fromURI({ uri: 'openid-initiate-issuance://?issuer=https%3A%2F%2Fissuer.research.identiproof.io&credential_type=OpenBadgeCredentialUrl&pre-authorized_code=4jLs9xZHEfqcoow0kHE7d1a8hUk6Sy-5bVSV2MqBUGUgiFFQi-ImL62T-FmLIo8hKA1UdMPH0lM1xAgcFkJfxIw9L-lI3mVs0hRT8YVwsEM1ma6N3wzuCdwtMU4bcwKp&user_pin_required=true', - flowType: AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW, // The flow to use kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21#key-1', // Our DID. You can defer this also to when the acquireCredential method is called alg: Alg.ES256, // The signing Algorithm we will use. You can defer this also to when the acquireCredential method is called clientId: 'test-clientId', // The clientId if the Authrozation Service requires it. If a clientId is needed you can defer this also to when the acquireAccessToken method is called diff --git a/packages/client/lib/AccessTokenClient.ts b/packages/client/lib/AccessTokenClient.ts index 5b669e39..bab1788f 100644 --- a/packages/client/lib/AccessTokenClient.ts +++ b/packages/client/lib/AccessTokenClient.ts @@ -4,10 +4,10 @@ import { AccessTokenResponse, assertedUniformCredentialOffer, AuthorizationServerOpts, + AuthzFlowType, EndpointMetadata, getIssuerFromCredentialOfferPayload, GrantTypes, - isPreAuthCode, IssuerOpts, OpenIDResponse, PRE_AUTH_CODE_LITERAL, @@ -67,6 +67,7 @@ export class AccessTokenClient { issuerOpts?: IssuerOpts; }): Promise> { this.validate(accessTokenRequest, isPinRequired); + const requestTokenURL = AccessTokenClient.determineTokenURL({ asOpts, issuerOpts, @@ -76,6 +77,7 @@ export class AccessTokenClient { ? await MetadataClient.retrieveAllMetadata(issuerOpts.issuer, { errorOnNotFound: false }) : undefined, }); + return this.sendAuthCode(requestTokenURL, accessTokenRequest); } @@ -83,38 +85,36 @@ export class AccessTokenClient { const { asOpts, pin, codeVerifier, code, redirectUri } = opts; const credentialOfferRequest = await toUniformCredentialOfferRequest(opts.credentialOffer); const request: Partial = {}; + if (asOpts?.clientId) { request.client_id = asOpts.clientId; } - this.assertNumericPin(this.isPinRequiredValue(credentialOfferRequest.credential_offer), pin); - request.user_pin = pin; + if (credentialOfferRequest.supportedFlows.includes(AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW)) { + this.assertNumericPin(this.isPinRequiredValue(credentialOfferRequest.credential_offer), pin); + request.user_pin = pin; - const isPreAuth = isPreAuthCode(credentialOfferRequest); - if (isPreAuth) { - if (codeVerifier) { - throw new Error('Cannot pass a code_verifier when flow type is pre-authorized'); - } request.grant_type = GrantTypes.PRE_AUTHORIZED_CODE; // we actually know it is there because of the isPreAuthCode call request[PRE_AUTH_CODE_LITERAL] = credentialOfferRequest?.credential_offer.grants?.['urn:ietf:params:oauth:grant-type:pre-authorized_code']?.[PRE_AUTH_CODE_LITERAL]; + + return request as AccessTokenRequest; } - if (!isPreAuth && credentialOfferRequest.credential_offer.grants?.authorization_code?.issuer_state) { - this.throwNotSupportedFlow(); // not supported yet + + if (credentialOfferRequest.supportedFlows.includes(AuthzFlowType.AUTHORIZATION_CODE_FLOW)) { request.grant_type = GrantTypes.AUTHORIZATION_CODE; - } - if (codeVerifier) { - request.code_verifier = codeVerifier; request.code = code; request.redirect_uri = redirectUri; - request.grant_type = GrantTypes.AUTHORIZATION_CODE; - } - if (request.grant_type === GrantTypes.AUTHORIZATION_CODE && isPreAuth) { - throw Error('A pre_authorized_code flow cannot have an issuer state in the credential offer'); + + if (codeVerifier) { + request.code_verifier = codeVerifier; + } + + return request as AccessTokenRequest; } - return request as AccessTokenRequest; + throw new Error('Credential offer request does not follow neither pre-authorized code nor authorization code flow requirements.'); } private assertPreAuthorizedGrantType(grantType: GrantTypes): void { diff --git a/packages/client/lib/OpenID4VCIClient.ts b/packages/client/lib/OpenID4VCIClient.ts index 592d2dfd..90aa0955 100644 --- a/packages/client/lib/OpenID4VCIClient.ts +++ b/packages/client/lib/OpenID4VCIClient.ts @@ -1,7 +1,6 @@ import { AccessTokenResponse, Alg, - AuthorizationRequestV1_0_09, AuthzFlowType, CodeChallengeMethod, CredentialOfferPayloadV1_0_08, @@ -9,9 +8,9 @@ import { CredentialResponse, CredentialSupported, EndpointMetadataResult, + JsonURIMode, OID4VCICredentialFormat, OpenId4VCIVersion, - OpenIDResponse, ProofOfPossessionCallbacks, PushedAuthorizationResponse, ResponseType, @@ -39,7 +38,6 @@ interface AuthDetails { } interface AuthRequestOpts { - clientId: string; codeChallenge: string; codeChallengeMethod: CodeChallengeMethod; authorizationDetails?: AuthDetails | AuthDetails[]; @@ -48,7 +46,6 @@ interface AuthRequestOpts { } export class OpenID4VCIClient { - private readonly _flowType: AuthzFlowType; private readonly _credentialOffer: CredentialOfferRequestWithBaseUrl; private _clientId?: string; private _kid: string | undefined; @@ -56,17 +53,7 @@ export class OpenID4VCIClient { private _endpointMetadata: EndpointMetadataResult | undefined; private _accessTokenResponse: AccessTokenResponse | undefined; - private constructor( - credentialOffer: CredentialOfferRequestWithBaseUrl, - flowType: AuthzFlowType, - kid?: string, - alg?: Alg | string, - clientId?: string, - ) { - if (!credentialOffer.supportedFlows.includes(flowType)) { - throw Error(`Flows ${flowType} is not supported by issuer ${credentialOffer.credential_offer_uri}`); - } - this._flowType = flowType; + private constructor(credentialOffer: CredentialOfferRequestWithBaseUrl, kid?: string, alg?: Alg | string, clientId?: string) { this._credentialOffer = credentialOffer; this._kid = kid; this._alg = alg; @@ -75,7 +62,6 @@ export class OpenID4VCIClient { public static async fromURI({ uri, - flowType, kid, alg, retrieveServerMetadata, @@ -83,14 +69,13 @@ export class OpenID4VCIClient { resolveOfferUri, }: { uri: string; - flowType: AuthzFlowType; kid?: string; alg?: Alg | string; retrieveServerMetadata?: boolean; resolveOfferUri?: boolean; clientId?: string; }): Promise { - const client = new OpenID4VCIClient(await CredentialOfferClient.fromURI(uri, { resolve: resolveOfferUri }), flowType, kid, alg, clientId); + const client = new OpenID4VCIClient(await CredentialOfferClient.fromURI(uri, { resolve: resolveOfferUri }), kid, alg, clientId); if (retrieveServerMetadata === undefined || retrieveServerMetadata) { await client.retrieveServerMetadata(); @@ -106,14 +91,7 @@ export class OpenID4VCIClient { return this.endpointMetadata; } - public createAuthorizationRequestUrl({ - clientId, - codeChallengeMethod, - codeChallenge, - authorizationDetails, - redirectUri, - scope, - }: AuthRequestOpts): string { + public createAuthorizationRequestUrl({ codeChallengeMethod, codeChallenge, authorizationDetails, redirectUri, scope }: AuthRequestOpts): string { // Scope and authorization_details can be used in the same authorization request // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rar-23#name-relationship-to-scope-param if (!scope && !authorizationDetails) { @@ -133,36 +111,42 @@ export class OpenID4VCIClient { } // add 'openid' scope if not present - if (scope && !scope.includes('openid')) { - scope = `openid ${scope}`; + if (!scope?.includes('openid')) { + scope = ['openid', scope].filter((s) => !!s).join(' '); } - //fixme: handle this for v11 - const queryObj = { + const queryObj: { [key: string]: string } = { response_type: ResponseType.AUTH_CODE, - client_id: clientId, code_challenge_method: codeChallengeMethod, code_challenge: codeChallenge, authorization_details: JSON.stringify(this.handleAuthorizationDetails(authorizationDetails)), redirect_uri: redirectUri, scope: scope, - } as AuthorizationRequestV1_0_09; + }; + + if (this.clientId) { + queryObj['client_id'] = this.clientId; + } + + if (this.credentialOffer.issuerState) { + queryObj['issuer_state'] = this.credentialOffer.issuerState; + } return convertJsonToURI(queryObj, { baseUrl: this._endpointMetadata.authorization_endpoint, - uriTypeProperties: ['redirect_uri', 'scope', 'authorization_details'], - version: this.version(), + uriTypeProperties: ['redirect_uri', 'scope', 'authorization_details', 'issuer_state'], + mode: JsonURIMode.X_FORM_WWW_URLENCODED, + // We do not add the version here, as this always needs to be form encoded }); } public async acquirePushedAuthorizationRequestURI({ - clientId, codeChallengeMethod, codeChallenge, authorizationDetails, redirectUri, scope, - }: AuthRequestOpts): Promise> { + }: AuthRequestOpts): Promise { // Scope and authorization_details can be used in the same authorization request // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rar-23#name-relationship-to-scope-param if (!scope && !authorizationDetails) { @@ -183,21 +167,37 @@ export class OpenID4VCIClient { const parEndpoint: string = this._endpointMetadata.credentialIssuerMetadata.pushed_authorization_request_endpoint; // add 'openid' scope if not present - if (scope && !scope.includes('openid')) { - scope = `openid ${scope}`; + if (!scope?.includes('openid')) { + scope = ['openid', scope].filter((s) => !!s).join(' '); } - //fixme: handle this for v11 - const queryObj: AuthorizationRequestV1_0_09 = { + const queryObj: { [key: string]: string } = { response_type: ResponseType.AUTH_CODE, - client_id: clientId, code_challenge_method: codeChallengeMethod, code_challenge: codeChallenge, authorization_details: JSON.stringify(this.handleAuthorizationDetails(authorizationDetails)), redirect_uri: redirectUri, scope: scope, }; - return await formPost(parEndpoint, JSON.stringify(queryObj)); + + if (this.clientId) { + queryObj['client_id'] = this.clientId; + } + + if (this.credentialOffer.issuerState) { + queryObj['issuer_state'] = this.credentialOffer.issuerState; + } + + const response = await formPost(parEndpoint, new URLSearchParams(queryObj)); + + return convertJsonToURI( + { request_uri: response.successBody?.request_uri }, + { + baseUrl: this._endpointMetadata.credentialIssuerMetadata.authorization_endpoint, + uriTypeProperties: ['request_uri'], + mode: JsonURIMode.X_FORM_WWW_URLENCODED, + }, + ); } public handleAuthorizationDetails(authorizationDetails?: AuthDetails | AuthDetails[]): AuthDetails | AuthDetails[] | undefined { @@ -237,7 +237,9 @@ export class OpenID4VCIClient { redirectUri?: string; }): Promise { const { pin, clientId, codeVerifier, code, redirectUri } = opts ?? {}; + this.assertIssuerData(); + if (clientId) { this._clientId = clientId; } @@ -300,24 +302,29 @@ export class OpenID4VCIClient { credentialOffer: this.credentialOffer, metadata: this.endpointMetadata, }); + requestBuilder.withTokenFromResponse(this.accessTokenResponse); if (this.endpointMetadata?.credentialIssuerMetadata) { const metadata = this.endpointMetadata.credentialIssuerMetadata; - const types = Array.isArray(credentialTypes) ? credentialTypes : [credentialTypes]; + const types = Array.isArray(credentialTypes) ? credentialTypes.sort() : [credentialTypes]; + if (metadata.credentials_supported && Array.isArray(metadata.credentials_supported)) { - for (const type of types) { - let typeSupported = false; - for (const credentialSupported of metadata.credentials_supported) { - if (!credentialSupported.types || credentialSupported.types.length === 0) { - throw Error('types is required in the credentials supported'); - } - if (credentialSupported.types.indexOf(type) != -1) { - typeSupported = true; - } + let typeSupported = false; + + metadata.credentials_supported.forEach((supportedCredential) => { + if (!supportedCredential.types || supportedCredential.types.length === 0) { + throw Error('types is required in the credentials supported'); } - if (!typeSupported) { - throw Error(`Not all credential types ${JSON.stringify(credentialTypes)} are supported by issuer ${this.getIssuer()}`); + if ( + supportedCredential.types.sort().every((t, i) => types[i] === t) || + (types.length === 1 && (types[0] === supportedCredential.id || supportedCredential.types.includes(types[0]))) + ) { + typeSupported = true; } + }); + + if (!typeSupported) { + throw Error(`Not all credential types ${JSON.stringify(credentialTypes)} are supported by issuer ${this.getIssuer()}`); } } else if (metadata.credentials_supported && !Array.isArray(metadata.credentials_supported)) { const credentialsSupported = metadata.credentials_supported as CredentialSupportedTypeV1_0_08; @@ -389,16 +396,12 @@ export class OpenID4VCIClient { result[0] = types; return result; } else { - return this.credentialOffer.credential_offer.credentials.map((c, index) => { + return this.credentialOffer.credential_offer.credentials.map((c) => { return typeof c === 'string' ? [c] : c.types; }); } } - get flowType(): AuthzFlowType { - return this._flowType; - } - issuerSupportedFlowTypes(): AuthzFlowType[] { return this.credentialOffer.supportedFlows; } diff --git a/packages/client/lib/__tests__/AccessTokenClient.spec.ts b/packages/client/lib/__tests__/AccessTokenClient.spec.ts index 52b7345a..045b2148 100644 --- a/packages/client/lib/__tests__/AccessTokenClient.spec.ts +++ b/packages/client/lib/__tests__/AccessTokenClient.spec.ts @@ -1,11 +1,4 @@ -import { - AccessTokenRequest, - AccessTokenRequestOpts, - AccessTokenResponse, - GrantTypes, - OpenIDResponse, - WellKnownEndpoints, -} from '@sphereon/oid4vci-common'; +import { AccessTokenRequest, AccessTokenResponse, GrantTypes, OpenIDResponse, WellKnownEndpoints } from '@sphereon/oid4vci-common'; import nock from 'nock'; import { AccessTokenClient } from '../AccessTokenClient'; @@ -204,24 +197,6 @@ describe('AccessTokenClient should', () => { ).rejects.toThrow(Error('Cannot set a pin, when the pin is not required.')); }); - it('get error if code_verifier is present when flow type is pre-authorized', async () => { - const accessTokenClient: AccessTokenClient = new AccessTokenClient(); - - nock(MOCK_URL).post(/.*/).reply(200, {}); - - const requestOpts: AccessTokenRequestOpts = { - credentialOffer: INITIATION_TEST, - pin: undefined, - codeVerifier: 'RylyWGQ-dzpObnEcoMBDIH9cTAwZXk1wYzktKxsOFgA', - code: 'LWCt225yj7gzT2cWeMP4hXj4B4oIYkEiGs4T6pfez91', - redirectUri: 'http://example.com/cb', - }; - - await expect(() => accessTokenClient.acquireAccessToken(requestOpts)).rejects.toThrow( - Error('Cannot pass a code_verifier when flow type is pre-authorized'), - ); - }); - it('get error if no as, issuer and metadata values are present', async () => { await expect(() => AccessTokenClient.determineTokenURL({ diff --git a/packages/client/lib/__tests__/IT.spec.ts b/packages/client/lib/__tests__/IT.spec.ts index 74c3a741..00ca84ea 100644 --- a/packages/client/lib/__tests__/IT.spec.ts +++ b/packages/client/lib/__tests__/IT.spec.ts @@ -1,7 +1,6 @@ import { AccessTokenResponse, Alg, - AuthzFlowType, CredentialOfferRequestWithBaseUrl, Jwt, OpenId4VCIVersion, @@ -72,7 +71,6 @@ describe('OID4VCI-Client should', () => { succeedWithAFullFlowWithClientSetup(); const client = await OpenID4VCIClient.fromURI({ uri: INITIATE_QR, - flowType: AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW, kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1', alg: Alg.ES256, clientId: 'test-clientId', @@ -84,7 +82,6 @@ describe('OID4VCI-Client should', () => { succeedWithAFullFlowWithClientSetup(); const client = await OpenID4VCIClient.fromURI({ uri: OFFER_QR, - flowType: AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW, kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1', alg: Alg.ES256, clientId: 'test-clientId', @@ -93,7 +90,6 @@ describe('OID4VCI-Client should', () => { }); async function assertionOfsucceedWithAFullFlowWithClient(client: OpenID4VCIClient) { - expect(client.flowType).toEqual(AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW); expect(client.credentialOffer).toBeDefined(); expect(client.endpointMetadata).toBeDefined(); expect(client.getIssuer()).toEqual('https://issuer.research.identiproof.io'); diff --git a/packages/client/lib/__tests__/MattrE2E.spec.test.ts b/packages/client/lib/__tests__/MattrE2E.spec.test.ts index 70f5f5f0..9000831c 100644 --- a/packages/client/lib/__tests__/MattrE2E.spec.test.ts +++ b/packages/client/lib/__tests__/MattrE2E.spec.test.ts @@ -1,4 +1,4 @@ -import { Alg, AuthzFlowType, Jwt } from '@sphereon/oid4vci-common'; +import { Alg, Jwt } from '@sphereon/oid4vci-common'; import { CredentialMapper } from '@sphereon/ssi-types'; import { fetch } from 'cross-fetch'; import { importJWK, JWK, SignJWT } from 'jose'; @@ -25,11 +25,9 @@ describe('OID4VCI-Client using Mattr issuer should', () => { const offer = await getCredentialOffer(format); const client = await OpenID4VCIClient.fromURI({ uri: offer.offerUrl, - flowType: AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW, kid, alg: Alg.EdDSA, }); - expect(client.flowType).toEqual(AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW); expect(client.credentialOffer).toBeDefined(); expect(client.endpointMetadata).toBeDefined(); expect(client.getCredentialEndpoint()).toEqual(`${ISSUER_URL}/oidc/v1/auth/credential`); diff --git a/packages/client/lib/__tests__/OpenID4VCIClient.spec.ts b/packages/client/lib/__tests__/OpenID4VCIClient.spec.ts index c3d9da59..d29100bd 100644 --- a/packages/client/lib/__tests__/OpenID4VCIClient.spec.ts +++ b/packages/client/lib/__tests__/OpenID4VCIClient.spec.ts @@ -1,4 +1,4 @@ -import { AuthzFlowType, CodeChallengeMethod, WellKnownEndpoints } from '@sphereon/oid4vci-common'; +import { CodeChallengeMethod, WellKnownEndpoints } from '@sphereon/oid4vci-common'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import nock from 'nock'; @@ -15,8 +15,8 @@ describe('OpenID4VCIClient should', () => { nock(MOCK_URL).get(WellKnownEndpoints.OAUTH_AS).reply(404, {}); nock(MOCK_URL).get(WellKnownEndpoints.OPENID_CONFIGURATION).reply(404, {}); client = await OpenID4VCIClient.fromURI({ + clientId: 'test-client', uri: 'openid-initiate-issuance://?issuer=https://server.example.com&credential_type=TestCredential', - flowType: AuthzFlowType.AUTHORIZATION_CODE_FLOW, }); }); @@ -29,7 +29,6 @@ describe('OpenID4VCIClient should', () => { // @ts-ignore client._endpointMetadata?.credentialIssuerMetadata.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`; const url = client.createAuthorizationRequestUrl({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', scope: 'openid TestCredential', @@ -44,7 +43,6 @@ describe('OpenID4VCIClient should', () => { it('throw an error if authorization endpoint is not set in server metadata', async () => { expect(() => { client.createAuthorizationRequestUrl({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', scope: 'openid TestCredential', @@ -58,7 +56,6 @@ describe('OpenID4VCIClient should', () => { client._endpointMetadata?.credentialIssuerMetadata.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`; const url = client.createAuthorizationRequestUrl({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', scope: 'TestCredential', @@ -77,7 +74,6 @@ describe('OpenID4VCIClient should', () => { expect(() => { client.createAuthorizationRequestUrl({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', redirectUri: 'http://localhost:8881/cb', @@ -91,7 +87,6 @@ describe('OpenID4VCIClient should', () => { expect( client.createAuthorizationRequestUrl({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', authorizationDetails: [ @@ -112,7 +107,7 @@ describe('OpenID4VCIClient should', () => { redirectUri: 'http://localhost:8881/cb', }), ).toEqual( - 'https://server.example.com/v1/auth/authorize?response_type=code&client_id=test-client&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb', + 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&scope=openid&client_id=test-client', ); }); it('create an authorization request url with authorization_details object property', async () => { @@ -122,7 +117,6 @@ describe('OpenID4VCIClient should', () => { expect( client.createAuthorizationRequestUrl({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', authorizationDetails: { @@ -136,7 +130,7 @@ describe('OpenID4VCIClient should', () => { redirectUri: 'http://localhost:8881/cb', }), ).toEqual( - 'https://server.example.com/v1/auth/authorize?response_type=code&client_id=test-client&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb', + 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&scope=openid&client_id=test-client', ); }); it('create an authorization request url with authorization_details and scope', async () => { @@ -146,7 +140,6 @@ describe('OpenID4VCIClient should', () => { expect( client.createAuthorizationRequestUrl({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', authorizationDetails: { @@ -162,7 +155,7 @@ describe('OpenID4VCIClient should', () => { redirectUri: 'http://localhost:8881/cb', }), ).toEqual( - 'https://server.example.com/v1/auth/authorize?response_type=code&client_id=test-client&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22locations%22%3A%5B%22https%3A%2F%2Ftest%2Ecom%22%2C%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&scope=openid', + 'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22locations%22%3A%5B%22https%3A%2F%2Ftest%2Ecom%22%2C%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&scope=openid&client_id=test-client', ); }); }); diff --git a/packages/client/lib/__tests__/OpenID4VCIClientPAR.spec.ts b/packages/client/lib/__tests__/OpenID4VCIClientPAR.spec.ts index 8a7e8ee6..bad3da3c 100644 --- a/packages/client/lib/__tests__/OpenID4VCIClientPAR.spec.ts +++ b/packages/client/lib/__tests__/OpenID4VCIClientPAR.spec.ts @@ -1,4 +1,4 @@ -import { AuthzFlowType, CodeChallengeMethod, WellKnownEndpoints } from '@sphereon/oid4vci-common'; +import { CodeChallengeMethod, WellKnownEndpoints } from '@sphereon/oid4vci-common'; import nock from 'nock'; import { OpenID4VCIClient } from '../OpenID4VCIClient'; @@ -13,8 +13,8 @@ describe('OpenID4VCIClient', () => { nock(MOCK_URL).get(WellKnownEndpoints.OPENID_CONFIGURATION).reply(404, {}); nock(`${MOCK_URL}`).post('/v1/auth/par').reply(201, { request_uri: 'test_uri', expires_in: 90 }); client = await OpenID4VCIClient.fromURI({ + clientId: 'test-client', uri: 'openid-initiate-issuance://?issuer=https://server.example.com&credential_type=TestCredential', - flowType: AuthzFlowType.AUTHORIZATION_CODE_FLOW, }); }); @@ -24,20 +24,19 @@ describe('OpenID4VCIClient', () => { it('should successfully retrieve the authorization code using PAR', async () => { client.endpointMetadata.credentialIssuerMetadata!.pushed_authorization_request_endpoint = `${MOCK_URL}v1/auth/par`; + client.endpointMetadata.credentialIssuerMetadata!.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`; const actual = await client.acquirePushedAuthorizationRequestURI({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', scope: 'openid TestCredential', redirectUri: 'http://localhost:8881/cb', }); - expect(actual.successBody).toEqual({ request_uri: 'test_uri', expires_in: 90 }); + expect(actual).toEqual('https://server.example.com/v1/auth/authorize?request_uri=test_uri'); }); it('should fail when pushed_authorization_request_endpoint is not present', async () => { await expect(() => client.acquirePushedAuthorizationRequestURI({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', scope: 'openid TestCredential', @@ -49,7 +48,6 @@ describe('OpenID4VCIClient', () => { it('should fail when authorization_details and scope are not present', async () => { await expect(() => client.acquirePushedAuthorizationRequestURI({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', redirectUri: 'http://localhost:8881/cb', @@ -59,8 +57,8 @@ describe('OpenID4VCIClient', () => { it('should not fail when only authorization_details is present', async () => { client.endpointMetadata.credentialIssuerMetadata!.pushed_authorization_request_endpoint = `${MOCK_URL}v1/auth/par`; + client.endpointMetadata.credentialIssuerMetadata!.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`; const actual = await client.acquirePushedAuthorizationRequestURI({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', authorizationDetails: [ @@ -75,25 +73,25 @@ describe('OpenID4VCIClient', () => { ], redirectUri: 'http://localhost:8881/cb', }); - expect(actual.successBody).toEqual({ request_uri: 'test_uri', expires_in: 90 }); + expect(actual).toEqual('https://server.example.com/v1/auth/authorize?request_uri=test_uri'); }); it('should not fail when only scope is present', async () => { client.endpointMetadata.credentialIssuerMetadata!.pushed_authorization_request_endpoint = `${MOCK_URL}v1/auth/par`; + client.endpointMetadata.credentialIssuerMetadata!.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`; const actual = await client.acquirePushedAuthorizationRequestURI({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', scope: 'openid TestCredential', redirectUri: 'http://localhost:8881/cb', }); - expect(actual.successBody).toEqual({ request_uri: 'test_uri', expires_in: 90 }); + expect(actual).toEqual('https://server.example.com/v1/auth/authorize?request_uri=test_uri'); }); it('should not fail when both authorization_details and scope are present', async () => { client.endpointMetadata.credentialIssuerMetadata!.pushed_authorization_request_endpoint = `${MOCK_URL}v1/auth/par`; + client.endpointMetadata.credentialIssuerMetadata!.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`; const actual = await client.acquirePushedAuthorizationRequestURI({ - clientId: 'test-client', codeChallengeMethod: CodeChallengeMethod.SHA256, codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs', authorizationDetails: [ @@ -109,6 +107,6 @@ describe('OpenID4VCIClient', () => { scope: 'openid TestCredential', redirectUri: 'http://localhost:8881/cb', }); - expect(actual.successBody).toEqual({ request_uri: 'test_uri', expires_in: 90 }); + expect(actual).toEqual('https://server.example.com/v1/auth/authorize?request_uri=test_uri'); }); }); diff --git a/packages/common/CHANGELOG.md b/packages/common/CHANGELOG.md index e5f23567..04271689 100644 --- a/packages/common/CHANGELOG.md +++ b/packages/common/CHANGELOG.md @@ -7,34 +7,20 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @sphereon/oid4vci-common - - - - ## [0.7.2](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.1...v0.7.2) (2023-09-28) - ### Bug Fixes -* id lookup against server metadata not working ([592ec4b](https://github.com/Sphereon-Opensource/OID4VCI/commit/592ec4b837898eb3022d19479d79b6065e7a0d9e)) - - - - +- id lookup against server metadata not working ([592ec4b](https://github.com/Sphereon-Opensource/OID4VCI/commit/592ec4b837898eb3022d19479d79b6065e7a0d9e)) ## [0.7.1](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.0...v0.7.1) (2023-09-28) - ### Bug Fixes -* Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) -* Fix credential offer matching against metadata ([3c23bab](https://github.com/Sphereon-Opensource/OID4VCI/commit/3c23bab83569e04a4b5846fed83ce00d68e8ddce)) -* Fix credential offer matching against metadata ([b79027f](https://github.com/Sphereon-Opensource/OID4VCI/commit/b79027fe601ecccb1373ba399419e14f5ec2d7ff)) -* relax auth_endpoint handling. Doesn't have to be available when doing pre-auth flow. Client handles errors anyway in case of auth/par flow ([cb5f9c1](https://github.com/Sphereon-Opensource/OID4VCI/commit/cb5f9c1c12285508c6d403814d032e8883a59e7d)) - - - - +- Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) +- Fix credential offer matching against metadata ([3c23bab](https://github.com/Sphereon-Opensource/OID4VCI/commit/3c23bab83569e04a4b5846fed83ce00d68e8ddce)) +- Fix credential offer matching against metadata ([b79027f](https://github.com/Sphereon-Opensource/OID4VCI/commit/b79027fe601ecccb1373ba399419e14f5ec2d7ff)) +- relax auth_endpoint handling. Doesn't have to be available when doing pre-auth flow. Client handles errors anyway in case of auth/par flow ([cb5f9c1](https://github.com/Sphereon-Opensource/OID4VCI/commit/cb5f9c1c12285508c6d403814d032e8883a59e7d)) # [0.7.0](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.6.0...v0.7.0) (2023-08-19) diff --git a/packages/common/lib/functions/Encoding.ts b/packages/common/lib/functions/Encoding.ts index b84a918a..e9310e29 100644 --- a/packages/common/lib/functions/Encoding.ts +++ b/packages/common/lib/functions/Encoding.ts @@ -1,4 +1,4 @@ -import { BAD_PARAMS, DecodeURIAsJsonOpts, EncodeJsonAsURIOpts, OpenId4VCIVersion, SearchValue } from '../types'; +import { BAD_PARAMS, DecodeURIAsJsonOpts, EncodeJsonAsURIOpts, JsonURIMode, OpenId4VCIVersion, SearchValue } from '../types'; /** * @function encodeJsonAsURI encodes a Json object into a URI @@ -30,10 +30,11 @@ export function convertJsonToURI( } let components: string; - if (opts?.version && opts.version > OpenId4VCIVersion.VER_1_0_08) { + if ((opts?.version && opts.version > OpenId4VCIVersion.VER_1_0_08 && !opts.mode) || opts?.mode === JsonURIMode.JSON_STRINGIFY) { // v11 changed from encoding every param to a encoded json object with a credential_offer param key components = encodeAndStripWhitespace(JSON.stringify(json)); } else { + // version 8 or lower, or mode is x-form-www-urlencoded for (const [key, value] of Object.entries(json)) { if (!value) { continue; diff --git a/packages/common/lib/types/CredentialIssuance.types.ts b/packages/common/lib/types/CredentialIssuance.types.ts index 0e45a56e..bf43a4cf 100644 --- a/packages/common/lib/types/CredentialIssuance.types.ts +++ b/packages/common/lib/types/CredentialIssuance.types.ts @@ -56,11 +56,17 @@ export type SearchValue = { [Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string; }; +export enum JsonURIMode { + JSON_STRINGIFY, + X_FORM_WWW_URLENCODED, +} + export type EncodeJsonAsURIOpts = { uriTypeProperties?: string[]; arrayTypeProperties?: string[]; baseUrl?: string; param?: string; + mode?: JsonURIMode; version?: OpenId4VCIVersion; }; diff --git a/packages/common/lib/types/Generic.types.ts b/packages/common/lib/types/Generic.types.ts index 381aa0b7..4266cc09 100644 --- a/packages/common/lib/types/Generic.types.ts +++ b/packages/common/lib/types/Generic.types.ts @@ -53,7 +53,7 @@ export interface CredentialIssuerMetadataOpts { authorization_server?: string; // OPTIONAL. Identifier of the OAuth 2.0 Authorization Server (as defined in [RFC8414]) the Credential Issuer relies on for authorization. If this element is omitted, the entity providing the Credential Issuer is also acting as the AS, i.e. the Credential Issuer's identifier is used as the OAuth 2.0 Issuer value to obtain the Authorization Server metadata as per [RFC8414]. token_endpoint?: string; display?: MetadataDisplay[]; // An array of objects, where each object contains display properties of a Credential Issuer for a certain language. Below is a non-exhaustive list of valid parameters that MAY be included: - credential_supplier_config?: CredentialSupplierConfig + credential_supplier_config?: CredentialSupplierConfig; } // For now we extend the opts above. Only difference is that the credential endpoint is optional in the Opts, as it can come from other sources. The value is however required in the eventual Issuer Metadata diff --git a/packages/issuer-rest/CHANGELOG.md b/packages/issuer-rest/CHANGELOG.md index 21d8261e..01c90b1f 100644 --- a/packages/issuer-rest/CHANGELOG.md +++ b/packages/issuer-rest/CHANGELOG.md @@ -5,33 +5,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ## [0.7.3](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.2...v0.7.3) (2023-09-30) - ### Bug Fixes -* allow token endpoint to be defined in metadata without triggering logic for external AS ([d99304c](https://github.com/Sphereon-Opensource/OID4VCI/commit/d99304cd02b92974785f516e8bd82900cc3e0925)) - - - - +- allow token endpoint to be defined in metadata without triggering logic for external AS ([d99304c](https://github.com/Sphereon-Opensource/OID4VCI/commit/d99304cd02b92974785f516e8bd82900cc3e0925)) ## [0.7.2](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.1...v0.7.2) (2023-09-28) **Note:** Version bump only for package @sphereon/oid4vci-issuer-server - - - - ## [0.7.1](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.0...v0.7.1) (2023-09-28) - ### Bug Fixes -* Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) - - - - +- Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) # [0.7.0](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.6.0...v0.7.0) (2023-08-19) diff --git a/packages/issuer-rest/lib/__tests__/ClientIssuerIT.spec.ts b/packages/issuer-rest/lib/__tests__/ClientIssuerIT.spec.ts index 6364a7b6..c19316be 100644 --- a/packages/issuer-rest/lib/__tests__/ClientIssuerIT.spec.ts +++ b/packages/issuer-rest/lib/__tests__/ClientIssuerIT.spec.ts @@ -5,7 +5,6 @@ import { OpenID4VCIClient } from '@sphereon/oid4vci-client' import { AccessTokenResponse, Alg, - AuthzFlowType, CredentialOfferSession, CredentialSupported, IssuerCredentialSubjectDisplay, @@ -207,7 +206,6 @@ describe('VcIssuer', () => { it('should create client from credential offer URI', async () => { client = await OpenID4VCIClient.fromURI({ uri, - flowType: AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW, kid: subjectDIDKey.didDocument.authentication[0], alg: 'ES256', }) diff --git a/packages/issuer/CHANGELOG.md b/packages/issuer/CHANGELOG.md index 685d8f03..ade20f70 100644 --- a/packages/issuer/CHANGELOG.md +++ b/packages/issuer/CHANGELOG.md @@ -7,29 +7,16 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @sphereon/oid4vci-issuer - - - - ## [0.7.2](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.1...v0.7.2) (2023-09-28) **Note:** Version bump only for package @sphereon/oid4vci-issuer - - - - ## [0.7.1](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.0...v0.7.1) (2023-09-28) - ### Bug Fixes -* Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) -* clearinterval ([214e3c6](https://github.com/Sphereon-Opensource/OID4VCI/commit/214e3c6d7ced9b27c50186db8ed876330230a6a5)) - - - - +- Better match credential offer types and formats onto issuer metadata ([4044c21](https://github.com/Sphereon-Opensource/OID4VCI/commit/4044c2175b4cbee16f44c8bb5499bba249ca4993)) +- clearinterval ([214e3c6](https://github.com/Sphereon-Opensource/OID4VCI/commit/214e3c6d7ced9b27c50186db8ed876330230a6a5)) # [0.7.0](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.6.0...v0.7.0) (2023-08-19) diff --git a/packages/issuer/lib/VcIssuer.ts b/packages/issuer/lib/VcIssuer.ts index baab7400..054ceb82 100644 --- a/packages/issuer/lib/VcIssuer.ts +++ b/packages/issuer/lib/VcIssuer.ts @@ -276,11 +276,11 @@ export class VcIssuer { } const credentialDataSupplierInput = opts.credentialDataSupplierInput ?? session.credentialDataSupplierInput - const result = await credentialDataSupplier({ + const result = await credentialDataSupplier({ ...cNonceState, - credentialRequest: opts.credentialRequest, - credentialSupplierConfig: this._issuerMetadata.credential_supplier_config, - credentialOffer /*todo: clientId: */, + credentialRequest: opts.credentialRequest, + credentialSupplierConfig: this._issuerMetadata.credential_supplier_config, + credentialOffer /*todo: clientId: */, ...(credentialDataSupplierInput && { credentialDataSupplierInput }), } as CredentialDataSupplierArgs) credential = result.credential diff --git a/packages/issuer/lib/__tests__/VcIssuer.spec.ts b/packages/issuer/lib/__tests__/VcIssuer.spec.ts index 4ff68ce6..dd5d9e97 100644 --- a/packages/issuer/lib/__tests__/VcIssuer.spec.ts +++ b/packages/issuer/lib/__tests__/VcIssuer.spec.ts @@ -1,7 +1,6 @@ import { OpenID4VCIClient } from '@sphereon/oid4vci-client' import { Alg, - AuthzFlowType, CredentialOfferLdpVcV1_0_11, CredentialOfferSession, CredentialSupported, @@ -153,7 +152,7 @@ describe('VcIssuer', () => { 'http://issuer-example.com?credential_offer=%7B%22grants%22%3A%7B%22authorization_code%22%3A%7B%22issuer_state%22%3A%22previously-created-state%22%7D%2C%22urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code%22%3A%7B%22pre-authorized_code%22%3A%22test_code%22%2C%22user_pin_required%22%3Atrue%7D%7D%2C%22credential_issuer%22%3A%22https%3A%2F%2Fissuer.research.identiproof.io%22%2C%22credentials%22%3A%5B%7B%22format%22%3A%22jwt_vc_json%22%2C%22types%22%3A%5B%22VerifiableCredential%22%5D%2C%22credentialSubject%22%3A%7B%22given_name%22%3A%7B%22name%22%3A%22given%20name%22%2C%22locale%22%3A%22en-US%22%7D%7D%2C%22cryptographic_suites_supported%22%3A%5B%22ES256K%22%5D%2C%22cryptographic_binding_methods_supported%22%3A%5B%22did%22%5D%2C%22id%22%3A%22UniversityDegree_JWT%22%2C%22display%22%3A%5B%7B%22name%22%3A%22University%20Credential%22%2C%22locale%22%3A%22en-US%22%2C%22logo%22%3A%7B%22url%22%3A%22https%3A%2F%2Fexampleuniversity.com%2Fpublic%2Flogo.png%22%2C%22alt_text%22%3A%22a%20square%20logo%20of%20a%20university%22%7D%2C%22background_color%22%3A%22%2312107c%22%2C%22text_color%22%3A%22%23FFFFFF%22%7D%5D%7D%5D%7D', ) - const client = await OpenID4VCIClient.fromURI({ uri, flowType: AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW }) + const client = await OpenID4VCIClient.fromURI({ uri }) expect(client.credentialOffer).toEqual({ baseUrl: 'http://issuer-example.com', credential_offer: { diff --git a/packages/issuer/lib/types/index.ts b/packages/issuer/lib/types/index.ts index 3582de42..71fc1ba3 100644 --- a/packages/issuer/lib/types/index.ts +++ b/packages/issuer/lib/types/index.ts @@ -1,10 +1,11 @@ import { AssertedUniformCredentialOffer, CNonceState, - CredentialDataSupplierInput, CredentialSupplierConfig, + CredentialDataSupplierInput, + CredentialSupplierConfig, JwtVerifyResult, OID4VCICredentialFormat, - UniformCredentialRequest + UniformCredentialRequest, } from '@sphereon/oid4vci-common' import { ICredential, W3CVerifiableCredential } from '@sphereon/ssi-types'