@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.
- package/dist/index.cjs +51 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +51 -10
- package/dist/index.js.map +1 -1
- package/package.json +20 -20
- package/src/agent/OID4VCIIssuer.ts +42 -23
- package/src/functions.ts +34 -10
- package/src/index.ts +1 -1
- package/src/types/IOID4VCIIssuer.ts +5 -1
|
@@ -1,31 +1,39 @@
|
|
|
1
|
+
import {retrieveWellknown} from '@sphereon/oid4vci-client'
|
|
1
2
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
AccessTokenResponse,
|
|
4
|
+
AuthorizationServerMetadata,
|
|
5
|
+
CredentialResponse,
|
|
6
|
+
IssuerMetadata,
|
|
7
|
+
OpenIDResponse,
|
|
8
|
+
WellKnownEndpoints,
|
|
8
9
|
} from '@sphereon/oid4vci-common'
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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 {
|
|
27
|
+
import {IssuerInstance} from '../IssuerInstance'
|
|
28
|
+
import {IOID4VCIIssuer} from '../types/IOID4VCIIssuer'
|
|
27
29
|
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|