Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:Sphereon-Opensource/OID4VCI into…
Browse files Browse the repository at this point in the history
… develop
  • Loading branch information
auer-martin committed Jul 25, 2024
2 parents 162f3e9 + 006d953 commit 981e262
Show file tree
Hide file tree
Showing 40 changed files with 11,272 additions and 7,551 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.15.1](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.15.0...v0.15.1) (2024-07-23)

### Bug Fixes

- oid4vci draft 13 typing ([6d0bfc9](https://github.com/Sphereon-Opensource/OID4VCI/commit/6d0bfc9227b1120913b773904ef991757cb9282a))
- txCode fixes [#117](https://github.com/Sphereon-Opensource/OID4VCI/issues/117) ([7d17d13](https://github.com/Sphereon-Opensource/OID4VCI/commit/7d17d13d3485c5b6b55ef876eba8f09c9f7a788b))

# [0.15.0](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.14.0...v0.15.0) (2024-07-15)

### Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"packages": ["packages/*"],
"version": "0.15.0",
"version": "0.15.1",
"npmClient": "pnpm",
"command": {
"publish": {
Expand Down
4 changes: 4 additions & 0 deletions packages/callback-example/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.15.1](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.15.0...v0.15.1) (2024-07-23)

**Note:** Version bump only for package @sphereon/oid4vci-callback-example

# [0.15.0](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.14.0...v0.15.0) (2024-07-15)

**Note:** Version bump only for package @sphereon/oid4vci-callback-example
Expand Down
4 changes: 2 additions & 2 deletions packages/callback-example/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sphereon/oid4vci-callback-example",
"version": "0.15.0",
"version": "0.15.1",
"description": "OpenID 4 Verifiable Credential Issuance issuer callback example",
"source": "lib/index.ts",
"main": "dist/index.js",
Expand All @@ -18,7 +18,7 @@
"@sphereon/oid4vci-client": "workspace:*",
"@sphereon/oid4vci-common": "workspace:*",
"@sphereon/oid4vci-issuer": "workspace:*",
"@sphereon/ssi-types": "0.26.1-next.6",
"@sphereon/ssi-types": "0.28.0",
"jose": "^4.10.0"
},
"devDependencies": {
Expand Down
6 changes: 6 additions & 0 deletions packages/client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.15.1](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.15.0...v0.15.1) (2024-07-23)

### Bug Fixes

- oid4vci draft 13 typing ([6d0bfc9](https://github.com/Sphereon-Opensource/OID4VCI/commit/6d0bfc9227b1120913b773904ef991757cb9282a))

# [0.15.0](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.14.0...v0.15.0) (2024-07-15)

### Features
Expand Down
59 changes: 32 additions & 27 deletions packages/client/lib/AuthorizationCodeClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import {
convertJsonToURI,
CreateRequestObjectMode,
CredentialConfigurationSupportedV1_0_13,
CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_13,
CredentialDefinitionJwtVcJsonV1_0_13,
CredentialOfferPayloadV1_0_13,
CredentialOfferRequestWithBaseUrl,
determineSpecVersionFromOffer,
EndpointMetadataResultV1_0_13,
formPost,
isW3cCredentialSupported,
JsonURIMode,
Jwt,
OID4VCICredentialFormat,
OpenId4VCIVersion,
PARMode,
PKCEOpts,
Expand Down Expand Up @@ -95,14 +97,17 @@ export const createAuthorizationRequestUrl = async ({
clientId?: string;
version?: OpenId4VCIVersion;
}): Promise<string> => {
function removeDisplayAndValueTypes(obj: any): void {
for (const prop in obj) {
function removeDisplayAndValueTypes(obj: any) {
const newObj = { ...obj };
for (const prop in newObj) {
if (['display', 'value_type'].includes(prop)) {
delete obj[prop];
} else if (typeof obj[prop] === 'object') {
removeDisplayAndValueTypes(obj[prop]);
delete newObj[prop];
} else if (typeof newObj[prop] === 'object') {
newObj[prop] = removeDisplayAndValueTypes(newObj[prop]);
}
}

return newObj;
}

const { redirectUri, requestObjectOpts = { requestObjectMode: CreateRequestObjectMode.NONE } } = authorizationRequest;
Expand All @@ -111,7 +116,7 @@ export const createAuthorizationRequestUrl = async ({
let { scope, authorizationDetails } = authorizationRequest;
const parMode = endpointMetadata?.credentialIssuerMetadata?.require_pushed_authorization_requests
? PARMode.REQUIRE
: (authorizationRequest.parMode ?? (client_id ? PARMode.AUTO : PARMode.NEVER));
: authorizationRequest.parMode ?? (client_id ? PARMode.AUTO : PARMode.NEVER);
// 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) {
Expand All @@ -127,42 +132,42 @@ export const createAuthorizationRequestUrl = async ({
? filterSupportedCredentials(credentialOffer.credential_offer as CredentialOfferPayloadV1_0_13, credentialConfigurationSupported)
: [];

// FIXME: complains about VCT for sd-jwt
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
authorizationDetails = creds.flatMap((cred) => {
const locations = [credentialOffer?.credential_offer.credential_issuer ?? endpointMetadata.issuer];

// TODO: credential_configuration_id seems to always be defined?
const credential_configuration_id: string | undefined = cred.configuration_id;
const vct: string | undefined = cred.vct;
let format: OID4VCICredentialFormat | undefined;
const format = credential_configuration_id ? undefined : cred.format;

if (!credential_configuration_id) {
format = cred.format;
}
if (!credential_configuration_id && !cred.format) {
throw Error('format is required in authorization details');
}

const meta: any = {};
const credential_definition = cred.credential_definition;
if (credential_definition?.type && !format) {
// ype: OPTIONAL. Array as defined in Appendix A.1.1.2. This claim contains the type values the Wallet requests authorization for at the Credential Issuer. It MUST be present if the claim format is present in the root of the authorization details object. It MUST not be present otherwise.
// It meens we have a config_id, already mapping it to an explicit format and types
delete credential_definition.type;
}
if (credential_definition.credentialSubject) {
removeDisplayAndValueTypes(credential_definition.credentialSubject);
// SD-JWT VC
const vct = cred.format === 'vc+sd-jwt' ? cred.vct : undefined;

// W3C credentials
let credential_definition: undefined | Partial<CredentialDefinitionJwtVcJsonV1_0_13 | CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_13> =
undefined;
if (isW3cCredentialSupported(cred)) {
credential_definition = {
...cred.credential_definition,
// type: OPTIONAL. Array as defined in Appendix A.1.1.2. This claim contains the type values the Wallet requests authorization for at the Credential Issuer. It MUST be present if the claim format is present in the root of the authorization details object. It MUST not be present otherwise.
// It meens we have a config_id, already mapping it to an explicit format and types
type: format ? cred.credential_definition.type : undefined,
credentialSubject: cred.credential_definition.credentialSubject
? removeDisplayAndValueTypes(cred.credential_definition.credentialSubject)
: undefined,
};
}

return {
type: 'openid_credential',
...meta,
locations,
...(credential_definition && { credential_definition }),
...(credential_configuration_id && { credential_configuration_id }),
...(format && { format }),
...(vct && { vct }),
...(cred.claims && { claims: removeDisplayAndValueTypes(JSON.parse(JSON.stringify(cred.claims))) }),
...(vct && { vct, claims: cred.claims ? removeDisplayAndValueTypes(cred.claims) : undefined }),
} as AuthorizationDetails;
});
if (!authorizationDetails || authorizationDetails.length === 0) {
Expand Down
2 changes: 1 addition & 1 deletion packages/client/lib/AuthorizationCodeClientV1_0_11.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const createAuthorizationRequestUrlV1_0_11 = async ({

const parMode = endpointMetadata?.credentialIssuerMetadata?.require_pushed_authorization_requests
? PARMode.REQUIRE
: (authorizationRequest.parMode ?? PARMode.AUTO);
: authorizationRequest.parMode ?? PARMode.AUTO;
// 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) {
Expand Down
16 changes: 7 additions & 9 deletions packages/client/lib/CredentialRequestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
getUniformFormat,
isDeferredCredentialResponse,
isValidURL,
JsonLdIssuerCredentialDefinition,
OID4VCICredentialFormat,
OpenId4VCIVersion,
OpenIDResponse,
Expand Down Expand Up @@ -203,7 +202,9 @@ export class CredentialRequestClient {
// TODO: we should move format specific logic
if (format === 'jwt_vc_json' || format === 'jwt_vc') {
return {
types,
credential_definition: {
type: types,
},
format,
proof,
...opts.subjectIssuance,
Expand All @@ -218,13 +219,10 @@ export class CredentialRequestClient {
proof,
...opts.subjectIssuance,

// Ignored because v11 does not have the context value, but it is required in v12
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
credential_definition: {
types,
...(opts.context && { '@context': opts.context }),
} as JsonLdIssuerCredentialDefinition,
type: types,
'@context': opts.context as string[],
},
};
} else if (format === 'vc+sd-jwt') {
if (types.length > 1) {
Expand All @@ -236,7 +234,7 @@ export class CredentialRequestClient {
proof,
vct: types[0],
...opts.subjectIssuance,
} as CredentialRequestV1_0_13;
};
}

throw new Error(`Unsupported format: ${format}`);
Expand Down
2 changes: 1 addition & 1 deletion packages/client/lib/OpenID4VCIClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ export class OpenID4VCIClient {
issuerSupportedFlowTypes(): AuthzFlowType[] {
return (
this.credentialOffer?.supportedFlows ??
(this._state.endpointMetadata?.credentialIssuerMetadata?.authorization_endpoint ?? this._state.endpointMetadata?.authorization_server
((this._state.endpointMetadata?.credentialIssuerMetadata?.authorization_endpoint ?? this._state.endpointMetadata?.authorization_server)
? [AuthzFlowType.AUTHORIZATION_CODE_FLOW]
: [])
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import { KeyObject } from 'crypto';

import {
Alg,
CredentialIssuerMetadataV1_0_13,
CredentialRequestV1_0_13,
Jwt,
JwtVerifyResult,
OpenId4VCIVersion,
ProofOfPossession,
} from '@sphereon/oid4vci-common';
import { Alg, CredentialIssuerMetadataV1_0_13, Jwt, JwtVerifyResult, OpenId4VCIVersion, ProofOfPossession } from '@sphereon/oid4vci-common';
import * as jose from 'jose';

import { CredentialRequestOpts, ProofOfPossessionBuilder } from '..';
Expand Down Expand Up @@ -112,7 +104,7 @@ describe('Credential Request Client Builder', () => {
.withKid(kid)
.build();
await proofOfPossessionVerifierCallbackFunction({ ...proof, kid });
const credentialRequest: CredentialRequestV1_0_13 = await credReqClient.createCredentialRequest({
const credentialRequest = await credReqClient.createCredentialRequest({
proofInput: proof,
credentialIdentifier: 'OpenBadgeCredential',
version: OpenId4VCIVersion.VER_1_0_13,
Expand Down Expand Up @@ -142,7 +134,7 @@ describe('Credential Request Client Builder', () => {
.withKid(kid_withoutDid)
.build();
await proofOfPossessionVerifierCallbackFunction({ ...proof, kid: kid_withoutDid });
const credentialRequest: CredentialRequestV1_0_13 = await credReqClient.createCredentialRequest({
const credentialRequest = await credReqClient.createCredentialRequest({
proofInput: proof,
credentialTypes: 'OpenBadgeCredential',
version: OpenId4VCIVersion.VER_1_0_13,
Expand Down
8 changes: 4 additions & 4 deletions packages/client/lib/__tests__/SdJwt.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
AccessTokenRequest,
CredentialConfigurationSupportedSdJwtVcV1_0_13,
CredentialConfigurationSupportedV1_0_13,
CredentialRequestV1_0_13,
CredentialSupportedSdJwtVc,
} from '@sphereon/oid4vci-common';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
Expand Down Expand Up @@ -109,7 +109,7 @@ describe('sd-jwt vc', () => {
const supported = client.getCredentialsSupported('vc+sd-jwt');
expect(supported).toEqual({ SdJwtCredentialId: { format: 'vc+sd-jwt', id: 'SdJwtCredentialId', vct: 'SdJwtCredentialId' } });

const offered = supported['SdJwtCredentialId'] as CredentialSupportedSdJwtVc;
const offered = supported['SdJwtCredentialId'] as CredentialConfigurationSupportedSdJwtVcV1_0_13;

nock(issuerMetadata.token_endpoint as string)
.post('/')
Expand All @@ -130,7 +130,7 @@ describe('sd-jwt vc', () => {
.post('/')
.reply(200, async (_, body) =>
vcIssuer.issueCredential({
credentialRequest: { ...(body as CredentialRequestV1_0_13), credential_identifier: offered.vct },
credentialRequest: { ...(body as any), credential_identifier: 'SdJwtCredentialId' },
credential: {
vct: 'Hello',
iss: 'did:example:123',
Expand Down Expand Up @@ -233,7 +233,7 @@ describe('sd-jwt vc', () => {
.post('/')
.reply(200, async (_, body) =>
vcIssuer.issueCredential({
credentialRequest: { ...(body as CredentialRequestV1_0_13), credential_identifier: offered.vct },
credentialRequest: { ...(body as any), credential_identifier: offered.vct },
credential: {
vct: 'Hello',
iss: 'example.com',
Expand Down
6 changes: 3 additions & 3 deletions packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sphereon/oid4vci-client",
"version": "0.15.0",
"version": "0.15.1",
"description": "OpenID for Verifiable Credential Issuance (OpenID4VCI) client",
"source": "lib/index.ts",
"main": "dist/index.js",
Expand All @@ -16,12 +16,12 @@
},
"dependencies": {
"@sphereon/oid4vci-common": "workspace:*",
"@sphereon/ssi-types": "0.26.1-next.132",
"@sphereon/ssi-types": "0.28.0",
"cross-fetch": "^3.1.8",
"debug": "^4.3.5"
},
"devDependencies": {
"@sphereon/ssi-sdk-ext.key-utils": "^0.22.0",
"@sphereon/ssi-sdk-ext.key-utils": "^0.23.0",
"@transmute/did-key.js": "^0.3.0-unstable.10",
"@trust/keyto": "^2.0.0-alpha1",
"@types/jest": "^29.5.12",
Expand Down
6 changes: 6 additions & 0 deletions packages/common/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.15.1](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.15.0...v0.15.1) (2024-07-23)

### Bug Fixes

- oid4vci draft 13 typing ([6d0bfc9](https://github.com/Sphereon-Opensource/OID4VCI/commit/6d0bfc9227b1120913b773904ef991757cb9282a))

# [0.15.0](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.14.0...v0.15.0) (2024-07-15)

### Features
Expand Down
35 changes: 22 additions & 13 deletions packages/common/lib/functions/CredentialRequestUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,28 @@ export function getTypesFromRequest(credentialRequest: CredentialRequest, opts?:
let types: string[] = [];
if ('credential_identifier' in credentialRequest && credentialRequest.credential_identifier) {
throw Error(`Cannot get types from request when it contains a credential_identifier`);
} else if (credentialRequest.format === 'jwt_vc_json' || credentialRequest.format === 'jwt_vc') {
types = 'types' in credentialRequest ? credentialRequest.types : [];
} else if (credentialRequest.format === 'jwt_vc_json-ld' || credentialRequest.format === 'ldp_vc') {
types =
'credential_definition' in credentialRequest && credentialRequest.credential_definition
? credentialRequest.credential_definition.types
: // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
'types' in credentialRequest.types
? (credentialRequest['types' as keyof CredentialRequest] as unknown as string[])
: [];
} else if (credentialRequest.format === 'vc+sd-jwt') {
types = 'vct' in credentialRequest ? [credentialRequest.vct as string] : [];
} else if (
credentialRequest.format === 'jwt_vc_json-ld' ||
credentialRequest.format === 'ldp_vc' ||
credentialRequest.format === 'jwt_vc' ||
credentialRequest.format === 'jwt_vc_json'
) {
if ('credential_definition' in credentialRequest && credentialRequest.credential_definition) {
types =
'types' in credentialRequest.credential_definition
? credentialRequest.credential_definition.types
: credentialRequest.credential_definition.type;
}

if ('type' in credentialRequest && Array.isArray(credentialRequest.type)) {
types = credentialRequest.type;
}

if ('types' in credentialRequest && Array.isArray(credentialRequest.types)) {
types = credentialRequest.types;
}
} else if (credentialRequest.format === 'vc+sd-jwt' && 'vct' in credentialRequest) {
types = [credentialRequest.vct];
}

if (!types || types.length === 0) {
Expand Down
Loading

0 comments on commit 981e262

Please sign in to comment.