Skip to content

Commit

Permalink
feat: added support for creating offer deeplink from object and test …
Browse files Browse the repository at this point in the history
…it. plus some refactors

Signed-off-by: sksadjad <[email protected]>
  • Loading branch information
sksadjad committed Apr 6, 2023
1 parent bd1569c commit a87dcb1
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 42 deletions.
7 changes: 1 addition & 6 deletions packages/common/lib/types/Generic.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,11 @@ export interface SupportedCredentialIssuerMetadataJwtVcJson extends CredentialSu
order?: string[]; //An array of claims.display.name values that lists them in the order they should be displayed by the Wallet.
}

export interface CredentialOfferCredential {
export interface CredentialOfferFormat {
format: CredentialFormatEnum;
types: string[];
}

export interface CredentialOfferCredentialJwtVcJson extends CredentialOfferCredential {
format: CredentialFormatEnum.jwt_vc_json;
types: string[];
}

export interface IssuerCredentialDefinition {
'@context': ICredentialContextType[];
types: string[];
Expand Down
4 changes: 2 additions & 2 deletions packages/common/lib/types/v1_0_09.types.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { CommonAuthorizationRequest } from './Authorization.types';
import { CredentialOfferPayload } from './CredentialIssuance.types';
import { CredentialOfferCredentialJwtVcJson } from './Generic.types';
import { CredentialOfferFormat } from './Generic.types';

// https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-09.html#name-issuance-initiation-request
export interface CredentialOfferV1_0_09 {
issuer: string; //(url) REQUIRED The issuer URL of the Credential issuer, the Wallet is requested to obtain one or more Credentials from.
credential_type: string[] | string; //(url) REQUIRED A JSON string denoting the type of the Credential the Wallet shall request
credentials: CredentialOfferCredentialJwtVcJson[];
credentials: CredentialOfferFormat[];
'pre-authorized_code'?: string; //CONDITIONAL the code representing the issuer's authorization for the Wallet to obtain Credentials of a certain type. This code MUST be short-lived and single-use. MUST be present in a pre-authorized code flow.
user_pin_required?: boolean | string; //OPTIONAL Boolean value specifying whether the issuer expects presentation of a user PIN along with the Token Request in a pre-authorized code flow. Default is false.
op_state?: string; //(JWT) OPTIONAL String value created by the Credential Issuer and opaque to the Wallet that is used to bind the subsequent authentication request with the Credential Issuer to a context set up during previous steps
Expand Down
6 changes: 3 additions & 3 deletions packages/common/lib/types/v1_0_11.types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AuthorizationDetailsJwtVcJson, CommonAuthorizationRequest } from './Authorization.types';
import { CredentialOfferPayload } from './CredentialIssuance.types';
import { CredentialOfferCredential, Grant, IssuerCredentialDefinition } from './Generic.types';
import { CredentialOfferFormat, Grant, IssuerCredentialDefinition } from './Generic.types';

export interface CredentialOfferV1_0_11 {
credential_offer?: CommonCredentialOfferPayloadV1_0_11;
Expand All @@ -19,7 +19,7 @@ export interface CommonCredentialOfferPayloadV1_0_11 {
* credentials_supported Credential Issuer metadata parameter.
* When processing, the Wallet MUST resolve this string value to the respective object.
*/
credentials?: (CredentialOfferCredential | string)[];
credentials?: (CredentialOfferFormat | string)[];
/**
* OPTIONAL. A JSON object indicating to the Wallet the Grant Types the Credential Issuer's AS is prepared
* to process for this credential offer. Every grant is represented by a key and an object.
Expand All @@ -43,7 +43,7 @@ export interface CredentialOfferJwtVcJsonLdAndLdpVcV1_0_11 extends CommonCredent
}

export interface CredentialOfferJwtVcJsonV1_0_11 extends CommonCredentialOfferPayloadV1_0_11 {
credentials: (CredentialOfferCredential | string)[]; // look at CommonCredentialOfferPayloadV1_0_11.credentials
credentials: (CredentialOfferFormat | string)[]; // look at CommonCredentialOfferPayloadV1_0_11.credentials
}

export type CredentialOfferPayloadV1_0_11 = CredentialOfferJwtVcJsonLdAndLdpVcV1_0_11 | CredentialOfferJwtVcJsonV1_0_11;
Expand Down
6 changes: 5 additions & 1 deletion packages/issuer-rest/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,11 @@ export class RestAPI {
const preAuthorizedCode = request.params.pre_authorized_code
const id = uuidv4()
this.tokenToId.set(preAuthorizedCode, id)
return response.send(createCredentialOfferDeeplink(preAuthorizedCode, this._vcIssuer._issuerMetadata))
return response.send(
createCredentialOfferDeeplink(this._vcIssuer._issuerMetadata, {
preAuthorizedCode: preAuthorizedCode,
})
)
})
}
}
Expand Down
27 changes: 27 additions & 0 deletions packages/issuer/lib/__tests__/CredentialOfferUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { CredentialFormatEnum } from '@sphereon/openid4vci-common'

import { createCredentialOfferDeeplink } from '../index'

describe('CredentialOfferUtils should', () => {
it('create a deeplink from credentialOffer object', () => {
// below is the example from spec (https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-11.html#name-sending-credential-offer-by) and is wrong, the issuer_state should be in the grants and not a top-level property
// openid-credential-offer://credential_offer=%7B%22credential_issuer%22:%22https://credential-issuer.example.com%22,%22credentials%22:%5B%7B%22format%22:%22jwt_vc_json%22,%22types%22:%5B%22VerifiableCredential%22,%22UniversityDegreeCredential%22%5D%7D%5D,%22issuer_state%22:%22eyJhbGciOiJSU0Et...FYUaBy%22%7D
const credentialOffer = {
credential_issuer: 'https://credential-issuer.example.com',
credentials: [
{
format: CredentialFormatEnum.jwt_vc_json,
types: ['VerifiableCredential', 'UniversityDegreeCredential'],
},
],
grants: {
authorization_code: {
issuer_state: 'eyJhbGciOiJSU0Et...FYUaBy',
},
},
}
expect(createCredentialOfferDeeplink(undefined, { credentialOffer })).toEqual(
'openid-credential-offer://?credential_offer=credential_issuer=https%3A%2F%2Fcredential-issuer.example.com&credentials=%5B%7B%22format%22%3A%22jwt_vc_json%22%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%5D&grants=%7B%22authorization_code%22%3A%7B%22issuer_state%22%3A%22eyJhbGciOiJSU0Et...FYUaBy%22%7D%7D'
)
})
})
29 changes: 0 additions & 29 deletions packages/issuer/lib/functions/CredentialOffer.ts

This file was deleted.

37 changes: 37 additions & 0 deletions packages/issuer/lib/functions/CredentialOfferUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { CredentialOfferPayload, CredentialOfferPayloadV1_0_11, encodeJsonAsURI, IssuerMetadata } from '@sphereon/openid4vci-common'
import { v4 as uuidv4 } from 'uuid'

export function createCredentialOfferDeeplink(
issuerMetadata?: IssuerMetadata,
opts?: { state?: string; credentialOffer?: CredentialOfferPayload; preAuthorizedCode?: string; userPinRequired?: boolean }
): string {
// openid-credential-offer://credential_offer=%7B%22credential_issuer%22:%22https://credential-issuer.example.com
// %22,%22credentials%22:%5B%7B%22format%22:%22jwt_vc_json%22,%22types%22:%5B%22VerifiableCr
// edential%22,%22UniversityDegreeCredential%22%5D%7D%5D,%22issuer_state%22:%22eyJhbGciOiJSU0Et...
// FYUaBy%22%7D
if (!issuerMetadata && !opts?.credentialOffer) {
throw new Error('You have to provide issuerMetadata or credentialOffer object for creating a deeplink')
}
if (opts?.credentialOffer) {
return `openid-credential-offer://?credential_offer=${encodeJsonAsURI(opts.credentialOffer)}`
}
const credentialOfferPayload = {
credential_issuer: issuerMetadata?.credential_issuer,
credentials: issuerMetadata?.credentials_supported,
grants: {
authorization_code: {
issuer_state: opts && opts.state ? opts.state : uuidv4(),
},
},
} as CredentialOfferPayloadV1_0_11
if (opts?.preAuthorizedCode) {
if (!credentialOfferPayload.grants) {
credentialOfferPayload.grants = {}
}
credentialOfferPayload.grants['urn:ietf:params:oauth:grant-type:pre-authorized_code'] = {
'pre-authorized_code': opts.preAuthorizedCode,
user_pin_required: opts.userPinRequired ? opts.userPinRequired : false,
}
}
return `openid-credential-offer://?credential_offer=${encodeJsonAsURI(credentialOfferPayload)}`
}
2 changes: 1 addition & 1 deletion packages/issuer/lib/functions/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './CredentialOffer'
export * from './CredentialOfferUtils'

0 comments on commit a87dcb1

Please sign in to comment.