@sphereon/ssi-sdk.oid4vci-issuer 0.36.1-next.11 → 0.36.1-next.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,31 +1,39 @@
1
+ import {retrieveWellknown} from '@sphereon/oid4vci-client'
1
2
  import {
2
- AccessTokenResponse,
3
- AuthorizationServerMetadata,
4
- CredentialResponse,
5
- IssuerMetadata,
6
- OpenIDResponse,
7
- WellKnownEndpoints,
3
+ AccessTokenResponse,
4
+ AuthorizationServerMetadata,
5
+ CredentialResponse,
6
+ IssuerMetadata,
7
+ OpenIDResponse,
8
+ WellKnownEndpoints,
8
9
  } from '@sphereon/oid4vci-common'
9
- import { assertValidAccessTokenRequest, createAccessTokenResponse, VcIssuer } from '@sphereon/oid4vci-issuer'
10
- import { retrieveWellknown } from '@sphereon/oid4vci-client'
11
- import { getAgentResolver } from '@sphereon/ssi-sdk-ext.did-utils'
12
- import { IMetadataOptions } from '@sphereon/ssi-sdk.oid4vci-issuer-store'
13
- import { IAgentPlugin } from '@veramo/core'
14
- import { getAccessTokenSignerCallback } from '../functions'
10
+ import {assertValidAccessTokenRequest, createAccessTokenResponse, VcIssuer} from '@sphereon/oid4vci-issuer'
11
+ import {getAgentResolver} from '@sphereon/ssi-sdk-ext.did-utils'
12
+ import {IMetadataOptions} from '@sphereon/ssi-sdk.oid4vci-issuer-store'
13
+ import {IAgentPlugin} from '@veramo/core'
14
+ import {getAccessTokenSignerCallback} from '../functions'
15
15
  import {
16
- IAssertValidAccessTokenArgs,
17
- ICreateCredentialOfferURIResult,
18
- ICreateOfferArgs,
19
- IIssueCredentialArgs,
20
- IIssuerInstanceArgs,
21
- IIssuerOptions,
22
- IOID4VCIIssuerOpts,
23
- IRequiredContext,
24
- schema,
16
+ IAssertValidAccessTokenArgs,
17
+ ICreateCredentialOfferURIResult,
18
+ ICreateOfferArgs,
19
+ IIssueCredentialArgs,
20
+ IIssuerInstanceArgs,
21
+ IIssuerOptions,
22
+ IOID4VCIIssuerOpts,
23
+ IRefreshInstanceMetadata,
24
+ IRequiredContext,
25
+ schema,
25
26
  } from '../index'
26
- import { IssuerInstance } from '../IssuerInstance'
27
+ import {IssuerInstance} from '../IssuerInstance'
28
+ import {IOID4VCIIssuer} from '../types/IOID4VCIIssuer'
27
29
 
28
- import { IOID4VCIIssuer } from '../types/IOID4VCIIssuer'
30
+ export const oid4vciIssuerMethods: Array<string> = [
31
+ 'oid4vciCreateOfferURI',
32
+ 'oid4vciIssueCredential',
33
+ 'oid4vciCreateAccessTokenResponse',
34
+ 'oid4vciGetInstance',
35
+ 'oid4vciRefreshInstanceMetadata',
36
+ ]
29
37
 
30
38
  export class OID4VCIIssuer implements IAgentPlugin {
31
39
  private static readonly _DEFAULT_OPTS_KEY = '_default'
@@ -37,6 +45,7 @@ export class OID4VCIIssuer implements IAgentPlugin {
37
45
  oid4vciIssueCredential: this.oid4vciIssueCredential.bind(this),
38
46
  oid4vciCreateAccessTokenResponse: this.oid4vciCreateAccessTokenResponse.bind(this),
39
47
  oid4vciGetInstance: this.oid4vciGetInstance.bind(this),
48
+ oid4vciRefreshInstanceMetadata: this.oid4vciRefreshInstanceMetadata.bind(this),
40
49
  }
41
50
  private _opts: IOID4VCIIssuerOpts
42
51
 
@@ -146,6 +155,16 @@ export class OID4VCIIssuer implements IAgentPlugin {
146
155
  return this.oid4vciGetInstance(args, context)
147
156
  }
148
157
 
158
+ // TODO SSISDK-87 create proper solution to update issuer metadata
159
+ public async oid4vciRefreshInstanceMetadata(args: IRefreshInstanceMetadata, context: IRequiredContext): Promise<boolean> {
160
+ const instance = this.instances.get(args.credentialIssuer)
161
+ if (instance) {
162
+ instance.issuerMetadata = await this.getIssuerMetadata({ ...args }, context)
163
+ return true
164
+ }
165
+ return false
166
+ }
167
+
149
168
  public async oid4vciGetInstance(args: IIssuerInstanceArgs, context: IRequiredContext): Promise<IssuerInstance> {
150
169
  const credentialIssuer = args.credentialIssuer ?? OID4VCIIssuer._DEFAULT_OPTS_KEY
151
170
  //todo: prob doesn't make sense as credentialIssuer is mandatory anyway
package/src/functions.ts CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  } from '@sphereon/oid4vci-common'
13
13
  import { CredentialDataSupplier, CredentialIssuanceInput, CredentialSignerCallback, VcIssuer, VcIssuerBuilder } from '@sphereon/oid4vci-issuer'
14
14
  import { getAgentResolver, IDIDOptions } from '@sphereon/ssi-sdk-ext.did-utils'
15
- import { legacyKeyRefsToIdentifierOpts, ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
15
+ import { legacyKeyRefsToIdentifierOpts, ManagedIdentifierOptsOrResult, ManagedIdentifierResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
16
16
  import { contextHasPlugin } from '@sphereon/ssi-sdk.agent-config'
17
17
  import { SdJwtVcPayload } from '@sphereon/ssi-sdk.sd-jwt'
18
18
  import { IStatusListPlugin } from '@sphereon/ssi-sdk.vc-status-list'
@@ -25,6 +25,8 @@ import { Resolvable } from 'did-resolver'
25
25
  import { jwtDecode } from 'jwt-decode'
26
26
  import { IIssuerOptions, IRequiredContext } from './types/IOID4VCIIssuer'
27
27
 
28
+ const CLOCK_SKEW_ISSUANCE = 2 // Clock drift on Android is typically up to 2000ms, so we issue 2 seconds in the past
29
+
28
30
  export function getJwtVerifyCallback({ verifyOpts }: { verifyOpts?: JWTVerifyOptions }, _context: IRequiredContext) {
29
31
  return async (args: { jwt: string; kid?: string }): Promise<JwtVerifyResult> => {
30
32
  const resolver = getAgentResolver(_context, {
@@ -141,14 +143,20 @@ export async function getAccessTokenSignerCallback(
141
143
  },
142
144
  context: IRequiredContext,
143
145
  ) {
146
+ const resolution = legacyKeyRefsToIdentifierOpts(opts)
147
+ const identifier = await context.agent.identifierManagedGet({
148
+ identifier: resolution.identifier as string,
149
+ vmRelationship: 'authentication',
150
+ })
151
+
152
+ const keyRef = identifier.kmsKeyRef
153
+ if (!keyRef) {
154
+ throw Error('Cannot sign access tokens without a key ref')
155
+ }
156
+
144
157
  const signer = async (data: string | Uint8Array) => {
145
158
  let dataString, encoding: 'base64' | undefined
146
159
 
147
- const resolution = await legacyKeyRefsToIdentifierOpts(opts)
148
- const keyRef = resolution.kmsKeyRef
149
- if (!keyRef) {
150
- throw Error('Cannot sign access tokens without a key ref')
151
- }
152
160
  if (typeof data === 'string') {
153
161
  dataString = data
154
162
  encoding = undefined
@@ -168,6 +176,9 @@ export async function getAccessTokenSignerCallback(
168
176
  }
169
177
 
170
178
  let kidHeader: string | undefined = jwt?.header?.kid ?? kid
179
+ if (!kidHeader && identifier.kid) {
180
+ kidHeader = identifier.kid
181
+ }
171
182
  if (!kidHeader) {
172
183
  if (
173
184
  opts.idOpts?.method === 'did' ||
@@ -178,7 +189,13 @@ export async function getAccessTokenSignerCallback(
178
189
  kidHeader = opts.idOpts?.kid ?? opts.didOpts?.idOpts?.kid ?? opts?.didOpts?.identifierOpts?.kid
179
190
  }
180
191
  }
181
- return await createJWT(jwt.payload, { signer, issuer }, { ...jwt.header, ...(kidHeader && { kid: kidHeader }), typ: 'JWT' })
192
+
193
+ const alg = identifier.jwk?.alg
194
+ if (!alg) {
195
+ return Promise.reject(Error('No algorithm found in identifier JWK'))
196
+ }
197
+
198
+ return await createJWT(jwt.payload, { signer, issuer }, { ...jwt.header, ...(kidHeader && { kid: kidHeader }), typ: 'JWT', alg })
182
199
  }
183
200
 
184
201
  return accessTokenSignerCallback
@@ -201,7 +218,15 @@ export async function getCredentialSignerCallback(
201
218
  const credential = args.credential as ICredential // TODO: SDJWT
202
219
  let proofFormat: ProofFormat
203
220
 
204
- const resolution = await context.agent.identifierManagedGet(idOpts)
221
+ let resolution: ManagedIdentifierResult
222
+ if (typeof idOpts.identifier !== 'string') {
223
+ resolution = idOpts as ManagedIdentifierResult
224
+ } else {
225
+ resolution = await context.agent.identifierManagedGet({
226
+ identifier: idOpts.identifier,
227
+ vmRelationship: 'assertionMethod',
228
+ })
229
+ }
205
230
  proofFormat = format?.includes('ld') ? 'lds' : 'jwt'
206
231
  const issuer = resolution.issuer ?? resolution.kmsKeyRef
207
232
 
@@ -227,7 +252,6 @@ export async function getCredentialSignerCallback(
227
252
  const credentialStatusVC = await context.agent.slAddStatusToCredential({ credential, statusLists })
228
253
  if (credential.credentialStatus && !credential.credentialStatus.statusListCredential) {
229
254
  credential.credentialStatus = credentialStatusVC.credentialStatus
230
- // TODO update statusLists somehow?
231
255
  }
232
256
  }
233
257
 
@@ -246,7 +270,7 @@ export async function getCredentialSignerCallback(
246
270
  sdJwtPayload.iss = issuer
247
271
  }
248
272
  if (sdJwtPayload.iat === undefined) {
249
- sdJwtPayload.iat = Math.floor(new Date().getTime() / 1000)
273
+ sdJwtPayload.iat = Math.floor(new Date().getTime() / 1000) - CLOCK_SKEW_ISSUANCE
250
274
  }
251
275
 
252
276
  let disclosureFrame
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
  const schema = require('../plugin.schema.json')
5
5
  export { schema }
6
- export { OID4VCIIssuer } from './agent/OID4VCIIssuer'
6
+ export { OID4VCIIssuer, oid4vciIssuerMethods } from './agent/OID4VCIIssuer'
7
7
  export * from './functions'
8
8
  export * from './IssuerInstance'
9
9
  export * from './types/IOID4VCIIssuer'
@@ -30,6 +30,7 @@ export interface IOID4VCIIssuer extends IPluginMethodMap {
30
30
  oid4vciIssueCredential(issueArgs: IIssueCredentialArgs, context: IRequiredContext): Promise<CredentialResponse>
31
31
  oid4vciCreateAccessTokenResponse(accessTokenArgs: IAssertValidAccessTokenArgs, context: IRequiredContext): Promise<AccessTokenResponse>
32
32
  oid4vciGetInstance(args: IIssuerInstanceArgs, context: IRequiredContext): Promise<IssuerInstance>
33
+ oid4vciRefreshInstanceMetadata(args: IRefreshInstanceMetadata, context: IRequiredContext): Promise<boolean>
33
34
  }
34
35
 
35
36
  export interface IOID4VCIIssuerOpts {
@@ -45,7 +46,6 @@ export interface ICreateOfferArgs extends IIssuerInstanceArgs {
45
46
  credentialDefinition?: IssuerCredentialDefinition
46
47
  credentialOfferUri?: string
47
48
  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
48
-
49
49
  redirectUri?: string
50
50
  // auth_session?: string; Would be a nice extension to support, to allow external systems to determine what the auth_session value should be
51
51
  // @Deprecated use tx_code in the grant object
@@ -83,6 +83,10 @@ export interface IIssuerInstanceArgs {
83
83
  namespace?: string
84
84
  }
85
85
 
86
+ export interface IRefreshInstanceMetadata {
87
+ credentialIssuer: string
88
+ }
89
+
86
90
  export interface IIssuerInstanceOptions extends IMetadataOptions {
87
91
  issuerOpts?: IIssuerOptions
88
92
  metadataOpts?: CredentialIssuerMetadataOpts