@sphereon/ssi-sdk-ext.jwt-service 0.24.1-next.98 → 0.24.1-unstable.112
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/README.md +73 -374
- package/dist/agent/JwtService.d.ts +1 -0
- package/dist/agent/JwtService.d.ts.map +1 -1
- package/dist/agent/JwtService.js +7 -1
- package/dist/agent/JwtService.js.map +1 -1
- package/dist/functions/index.d.ts +17 -3
- package/dist/functions/index.d.ts.map +1 -1
- package/dist/functions/index.js +142 -12
- package/dist/functions/index.js.map +1 -1
- package/dist/types/IJwtService.d.ts +33 -8
- package/dist/types/IJwtService.d.ts.map +1 -1
- package/dist/types/IJwtService.js +15 -3
- package/dist/types/IJwtService.js.map +1 -1
- package/package.json +13 -13
- package/plugin.schema.json +2412 -112
- package/src/agent/JwtService.ts +9 -1
- package/src/functions/index.ts +168 -16
- package/src/types/IJwtService.ts +59 -13
package/src/agent/JwtService.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
CreateJwsJsonArgs,
|
|
7
7
|
createJwsJsonFlattened,
|
|
8
8
|
createJwsJsonGeneral,
|
|
9
|
+
IJwsValidationResult,
|
|
9
10
|
IJwtService,
|
|
10
11
|
IRequiredContext,
|
|
11
12
|
JwsCompactResult,
|
|
@@ -14,18 +15,21 @@ import {
|
|
|
14
15
|
PreparedJwsObject,
|
|
15
16
|
prepareJwsObject,
|
|
16
17
|
schema,
|
|
18
|
+
verifyJws,
|
|
19
|
+
VerifyJwsArgs,
|
|
17
20
|
} from '..'
|
|
18
21
|
|
|
19
22
|
/**
|
|
20
23
|
* @public
|
|
21
24
|
*/
|
|
22
25
|
export class JwtService implements IAgentPlugin {
|
|
23
|
-
readonly schema = schema.
|
|
26
|
+
readonly schema = schema.IJwtService
|
|
24
27
|
readonly methods: IJwtService = {
|
|
25
28
|
jwtPrepareJws: this.jwtPrepareJws.bind(this),
|
|
26
29
|
jwtCreateJwsJsonGeneralSignature: this.jwtCreateJwsJsonGeneralSignature.bind(this),
|
|
27
30
|
jwtCreateJwsJsonFlattenedSignature: this.jwtCreateJwsJsonFlattenedSignature.bind(this),
|
|
28
31
|
jwtCreateJwsCompactSignature: this.jwtCreateJwsCompactSignature.bind(this),
|
|
32
|
+
jwtVerifyJwsSignature: this.jwtVerifyJwsSignature.bind(this),
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
private async jwtPrepareJws(args: CreateJwsJsonArgs, context: IRequiredContext): Promise<PreparedJwsObject> {
|
|
@@ -44,4 +48,8 @@ export class JwtService implements IAgentPlugin {
|
|
|
44
48
|
// We wrap it in a json object for remote REST calls
|
|
45
49
|
return { jwt: await createJwsCompact(args, context) }
|
|
46
50
|
}
|
|
51
|
+
|
|
52
|
+
private async jwtVerifyJwsSignature(args: VerifyJwsArgs, context: IRequiredContext): Promise<IJwsValidationResult> {
|
|
53
|
+
return await verifyJws(args, context)
|
|
54
|
+
}
|
|
47
55
|
}
|
package/src/functions/index.ts
CHANGED
|
@@ -1,45 +1,70 @@
|
|
|
1
|
+
import { jwkTtoPublicKeyHex } from '@sphereon/ssi-sdk-ext.did-utils'
|
|
1
2
|
import {
|
|
3
|
+
ensureManagedIdentifierResult,
|
|
4
|
+
ExternalIdentifierDidOpts,
|
|
5
|
+
ExternalIdentifierX5cOpts,
|
|
6
|
+
IIdentifierResolution,
|
|
2
7
|
isManagedIdentifierDidResult,
|
|
3
8
|
isManagedIdentifierX5cResult,
|
|
4
9
|
ManagedIdentifierMethod,
|
|
5
10
|
ManagedIdentifierResult,
|
|
6
|
-
|
|
11
|
+
resolveExternalJwkIdentifier,
|
|
7
12
|
} from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
8
|
-
import {
|
|
13
|
+
import { keyTypeFromCryptographicSuite, verifySignatureWithSubtle } from '@sphereon/ssi-sdk-ext.key-utils'
|
|
14
|
+
import { contextHasPlugin } from '@sphereon/ssi-sdk.agent-config'
|
|
15
|
+
import { JWK } from '@sphereon/ssi-types'
|
|
16
|
+
import { IAgentContext } from '@veramo/core'
|
|
17
|
+
import { bytesToBase64url, decodeJoseBlob, encodeJoseBlob } from '@veramo/utils'
|
|
18
|
+
import { base64ToBytes } from '@veramo/utils'
|
|
9
19
|
import * as u8a from 'uint8arrays'
|
|
10
20
|
import {
|
|
11
21
|
CreateJwsCompactArgs,
|
|
12
22
|
CreateJwsFlattenedArgs,
|
|
13
23
|
CreateJwsJsonArgs,
|
|
14
|
-
|
|
24
|
+
IJwsValidationResult,
|
|
15
25
|
IRequiredContext,
|
|
26
|
+
isJwsCompact,
|
|
27
|
+
isJwsJsonFlattened,
|
|
28
|
+
isJwsJsonGeneral,
|
|
29
|
+
Jws,
|
|
16
30
|
JwsCompact,
|
|
31
|
+
JwsIdentifierMode,
|
|
17
32
|
JwsJsonFlattened,
|
|
18
33
|
JwsJsonGeneral,
|
|
34
|
+
JwsJsonGeneralWithIdentifiers,
|
|
19
35
|
JwsJsonSignature,
|
|
20
36
|
JwtHeader,
|
|
37
|
+
JwtPayload,
|
|
21
38
|
PreparedJwsObject,
|
|
39
|
+
VerifyJwsArgs,
|
|
22
40
|
} from '../types/IJwtService'
|
|
23
41
|
|
|
42
|
+
const payloadToBytes = (payload: string | JwtPayload | Uint8Array): Uint8Array => {
|
|
43
|
+
const isBytes = payload instanceof Uint8Array
|
|
44
|
+
const isString = typeof payload === 'string'
|
|
45
|
+
return isBytes ? payload : isString ? u8a.fromString(payload, 'base64url') : u8a.fromString(JSON.stringify(payload), 'utf-8')
|
|
46
|
+
}
|
|
47
|
+
|
|
24
48
|
export const prepareJwsObject = async (args: CreateJwsJsonArgs, context: IRequiredContext): Promise<PreparedJwsObject> => {
|
|
25
|
-
const { existingSignatures, protectedHeader, unprotectedHeader, issuer, payload, mode = 'auto' } = args
|
|
49
|
+
const { existingSignatures, protectedHeader, unprotectedHeader, issuer, payload, mode = 'auto', clientId, clientIdScheme } = args
|
|
26
50
|
|
|
27
51
|
const { noIdentifierInHeader = false } = issuer
|
|
28
|
-
const combinedHeader = { ...unprotectedHeader, ...protectedHeader }
|
|
29
|
-
if (!combinedHeader.alg) {
|
|
30
|
-
return Promise.reject(`No 'alg' key present in the JWS header`)
|
|
31
|
-
}
|
|
32
52
|
const identifier = await ensureManagedIdentifierResult(issuer, context)
|
|
33
53
|
await checkAndUpdateJwtHeader({ mode, identifier, noIdentifierInHeader, header: protectedHeader }, context)
|
|
34
|
-
|
|
35
54
|
const isBytes = payload instanceof Uint8Array
|
|
36
55
|
const isString = typeof payload === 'string'
|
|
37
56
|
if (!isBytes && !isString) {
|
|
38
57
|
if (issuer.noIssPayloadUpdate !== true && !payload.iss && identifier.issuer) {
|
|
39
58
|
payload.iss = identifier.issuer
|
|
40
59
|
}
|
|
60
|
+
if (clientIdScheme && !payload.client_id_scheme) {
|
|
61
|
+
payload.client_id_scheme = clientIdScheme
|
|
62
|
+
}
|
|
63
|
+
if (clientId && !payload.client_id) {
|
|
64
|
+
payload.client_id = clientId
|
|
65
|
+
}
|
|
41
66
|
}
|
|
42
|
-
const payloadBytes =
|
|
67
|
+
const payloadBytes = payloadToBytes(payload)
|
|
43
68
|
const base64urlHeader = encodeJoseBlob(protectedHeader)
|
|
44
69
|
const base64urlPayload = bytesToBase64url(payloadBytes)
|
|
45
70
|
|
|
@@ -120,24 +145,24 @@ export const checkAndUpdateJwtHeader = async (
|
|
|
120
145
|
header,
|
|
121
146
|
noIdentifierInHeader = false,
|
|
122
147
|
}: {
|
|
123
|
-
mode?:
|
|
148
|
+
mode?: JwsIdentifierMode
|
|
124
149
|
identifier: ManagedIdentifierResult
|
|
125
150
|
noIdentifierInHeader?: boolean
|
|
126
151
|
header: JwtHeader
|
|
127
152
|
},
|
|
128
153
|
context: IRequiredContext
|
|
129
154
|
) => {
|
|
130
|
-
if (
|
|
155
|
+
if (isIdentifierMode(mode, identifier.method, 'did')) {
|
|
131
156
|
// kid is VM of the DID
|
|
132
157
|
// @see https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.4
|
|
133
158
|
await checkAndUpdateDidHeader({ header, identifier, noIdentifierInHeader }, context)
|
|
134
|
-
} else if (
|
|
159
|
+
} else if (isIdentifierMode(mode, identifier.method, 'x5c')) {
|
|
135
160
|
// Include the x5c in the header. No kid
|
|
136
161
|
// @see https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.6
|
|
137
162
|
await checkAndUpdateX5cHeader({ header, identifier, noIdentifierInHeader }, context)
|
|
138
|
-
} else if (
|
|
163
|
+
} else if (isIdentifierMode(mode, identifier.method, 'kid', false)) {
|
|
139
164
|
await checkAndUpdateKidHeader({ header, identifier, noIdentifierInHeader }, context)
|
|
140
|
-
} else if (
|
|
165
|
+
} else if (isIdentifierMode(mode, identifier.method, 'jwk', false)) {
|
|
141
166
|
// Include the JWK in the header as well as its kid if present
|
|
142
167
|
// @see https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.3
|
|
143
168
|
// @see https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.4
|
|
@@ -262,7 +287,7 @@ const checkAndUpdateKidHeader = async (
|
|
|
262
287
|
}
|
|
263
288
|
}
|
|
264
289
|
|
|
265
|
-
const
|
|
290
|
+
const isIdentifierMode = (mode: JwsIdentifierMode, identifierMethod: ManagedIdentifierMethod, checkMode: JwsIdentifierMode, loose = true) => {
|
|
266
291
|
if (loose && (checkMode === 'jwk' || checkMode === 'kid')) {
|
|
267
292
|
// we always have the kid and jwk at hand no matter the identifier method, so we are okay with that
|
|
268
293
|
// todo: check the impact on the above expressions, as this will now always return true for the both of them
|
|
@@ -277,3 +302,130 @@ const isMode = (mode: CreateJwsMode, identifierMethod: ManagedIdentifierMethod,
|
|
|
277
302
|
// we always have the kid and jwk at hand no matter the identifier method, so we are okay with that
|
|
278
303
|
return mode === 'auto' && identifierMethod === checkMode
|
|
279
304
|
}
|
|
305
|
+
|
|
306
|
+
export const verifyJws = async (args: VerifyJwsArgs, context: IAgentContext<IIdentifierResolution>): Promise<IJwsValidationResult> => {
|
|
307
|
+
const jws = await toJwsJsonGeneralWithIdentifiers(args, context)
|
|
308
|
+
|
|
309
|
+
let errorMessages: string[] = []
|
|
310
|
+
let index = 0
|
|
311
|
+
await Promise.all(
|
|
312
|
+
jws.signatures.map(async (sigWithId) => {
|
|
313
|
+
// If we have a specific KMS agent plugin that can do the verification prefer that over the generic verification
|
|
314
|
+
index++
|
|
315
|
+
let valid: boolean
|
|
316
|
+
const data = u8a.fromString(`${sigWithId.protected}.${jws.payload}`, 'utf-8')
|
|
317
|
+
const jwkInfo = sigWithId.identifier.jwks[0]
|
|
318
|
+
if (sigWithId.header?.alg === 'RSA' && contextHasPlugin(context, 'keyManagerVerify')) {
|
|
319
|
+
const publicKeyHex = jwkTtoPublicKeyHex(jwkInfo.jwk)
|
|
320
|
+
valid = await context.agent.keyManagerVerify({
|
|
321
|
+
signature: sigWithId.signature,
|
|
322
|
+
data,
|
|
323
|
+
publicKeyHex,
|
|
324
|
+
type: keyTypeFromCryptographicSuite({ suite: jwkInfo.jwk.crv ?? 'ES256' }),
|
|
325
|
+
// no kms arg, as the current key manager needs a bit more work
|
|
326
|
+
})
|
|
327
|
+
} else {
|
|
328
|
+
const signature = base64ToBytes(sigWithId.signature)
|
|
329
|
+
valid = await verifySignatureWithSubtle({ data, signature, key: jwkInfo.jwk })
|
|
330
|
+
}
|
|
331
|
+
if (!valid) {
|
|
332
|
+
errorMessages.push(`Signature ${index} was not valid`)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return {
|
|
336
|
+
sigWithId,
|
|
337
|
+
valid,
|
|
338
|
+
}
|
|
339
|
+
})
|
|
340
|
+
)
|
|
341
|
+
const error = errorMessages.length !== 0
|
|
342
|
+
return {
|
|
343
|
+
name: 'jws',
|
|
344
|
+
jws,
|
|
345
|
+
error,
|
|
346
|
+
critical: error,
|
|
347
|
+
message: error ? errorMessages.join(', ') : 'Signature validated',
|
|
348
|
+
verificationTime: new Date(),
|
|
349
|
+
} satisfies IJwsValidationResult
|
|
350
|
+
}
|
|
351
|
+
export const toJwsJsonGeneral = async ({ jws }: { jws: Jws }, context: IAgentContext<any>): Promise<JwsJsonGeneral> => {
|
|
352
|
+
let payload: string
|
|
353
|
+
let signatures: JwsJsonSignature[] = []
|
|
354
|
+
|
|
355
|
+
if (isJwsCompact(jws)) {
|
|
356
|
+
const split = jws.split('.')
|
|
357
|
+
payload = split[1]
|
|
358
|
+
signatures[0] = {
|
|
359
|
+
protected: split[0],
|
|
360
|
+
signature: split[2],
|
|
361
|
+
} satisfies JwsJsonSignature
|
|
362
|
+
} else if (isJwsJsonGeneral(jws)) {
|
|
363
|
+
payload = jws.payload
|
|
364
|
+
signatures = jws.signatures
|
|
365
|
+
} else if (isJwsJsonFlattened(jws)) {
|
|
366
|
+
const { payload: _payload, ...signature } = jws
|
|
367
|
+
payload = _payload
|
|
368
|
+
signatures = [signature]
|
|
369
|
+
} else {
|
|
370
|
+
return Promise.reject(Error(`Invalid JWS supplied`))
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
payload,
|
|
374
|
+
signatures,
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async function resolveExternalIdentifierFromJwsHeader(
|
|
379
|
+
protectedHeader: JwtHeader,
|
|
380
|
+
context: IAgentContext<IIdentifierResolution>,
|
|
381
|
+
args: {
|
|
382
|
+
jws: Jws
|
|
383
|
+
opts?: { x5c?: Omit<ExternalIdentifierX5cOpts, 'identifier'>; did?: Omit<ExternalIdentifierDidOpts, 'identifier'> }
|
|
384
|
+
}
|
|
385
|
+
) {
|
|
386
|
+
if (protectedHeader.x5c) {
|
|
387
|
+
const x5c = protectedHeader.x5c
|
|
388
|
+
return await context.agent.identifierExternalResolveByX5c({
|
|
389
|
+
...args.opts?.x5c,
|
|
390
|
+
identifier: x5c,
|
|
391
|
+
verify: true,
|
|
392
|
+
})
|
|
393
|
+
} else if (protectedHeader.jwk) {
|
|
394
|
+
const jwk = protectedHeader.jwk
|
|
395
|
+
const x5c = jwk.x5c // todo resolve x5u
|
|
396
|
+
return await context.agent.identifierExternalResolveByJwk({
|
|
397
|
+
identifier: protectedHeader.jwk,
|
|
398
|
+
...(x5c && {
|
|
399
|
+
x5c: {
|
|
400
|
+
...args?.opts?.x5c,
|
|
401
|
+
identifier: x5c,
|
|
402
|
+
},
|
|
403
|
+
}),
|
|
404
|
+
})
|
|
405
|
+
} else if (protectedHeader.kid && protectedHeader.kid.startsWith('did:')) {
|
|
406
|
+
return await context.agent.identifierExternalResolveByDid({ ...args?.opts?.did, identifier: protectedHeader.kid })
|
|
407
|
+
} else {
|
|
408
|
+
return Promise.reject(Error(`We can only process DIDs, X.509 certificate chains and JWKs for signature validation at present`))
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export const toJwsJsonGeneralWithIdentifiers = async (
|
|
413
|
+
args: {
|
|
414
|
+
jws: Jws
|
|
415
|
+
jwk?: JWK
|
|
416
|
+
opts?: { x5c?: Omit<ExternalIdentifierX5cOpts, 'identifier'>; did?: Omit<ExternalIdentifierDidOpts, 'identifier'> }
|
|
417
|
+
},
|
|
418
|
+
context: IAgentContext<IIdentifierResolution>
|
|
419
|
+
): Promise<JwsJsonGeneralWithIdentifiers> => {
|
|
420
|
+
const jws = await toJwsJsonGeneral(args, context)
|
|
421
|
+
const signatures = await Promise.all(
|
|
422
|
+
jws.signatures.map(async (signature) => {
|
|
423
|
+
const protectedHeader: JwtHeader = decodeJoseBlob(signature.protected)
|
|
424
|
+
const identifier = args.jwk
|
|
425
|
+
? await resolveExternalJwkIdentifier({ identifier: args.jwk }, context)
|
|
426
|
+
: await resolveExternalIdentifierFromJwsHeader(protectedHeader, context, args)
|
|
427
|
+
return { ...signature, identifier }
|
|
428
|
+
})
|
|
429
|
+
)
|
|
430
|
+
return { payload: jws.payload, signatures }
|
|
431
|
+
}
|
package/src/types/IJwtService.ts
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import {
|
|
2
|
+
ExternalIdentifierDidOpts,
|
|
3
|
+
ExternalIdentifierResult,
|
|
4
|
+
ExternalIdentifierX5cOpts,
|
|
5
|
+
IIdentifierResolution,
|
|
6
|
+
ManagedIdentifierOptsOrResult,
|
|
7
|
+
ManagedIdentifierResult,
|
|
8
|
+
} from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
9
|
+
import { ClientIdScheme } from '@sphereon/ssi-sdk-ext.x509-utils'
|
|
10
|
+
import { IValidationResult, JoseSignatureAlgorithm, JoseSignatureAlgorithmString, JWK } from '@sphereon/ssi-types'
|
|
11
|
+
import { IAgentContext, IKeyManager, IPluginMethodMap } from '@veramo/core'
|
|
12
|
+
|
|
13
|
+
export type IRequiredContext = IAgentContext<IIdentifierResolution & IKeyManager> // could we still interop with Veramo?
|
|
7
14
|
|
|
8
15
|
export const jwtServiceContextMethods: Array<string> = [
|
|
9
16
|
'jwtPrepareJws',
|
|
10
17
|
'jwtCreateJwsJsonGeneralSignature',
|
|
11
18
|
'jwtCreateJwsJsonFlattenedSignature',
|
|
12
19
|
'jwtCreateJwsCompactSignature',
|
|
13
|
-
'
|
|
20
|
+
'jwtVerifyJwsSignature',
|
|
14
21
|
]
|
|
22
|
+
|
|
15
23
|
export interface IJwtService extends IPluginMethodMap {
|
|
16
24
|
jwtPrepareJws(args: CreateJwsJsonArgs, context: IRequiredContext): Promise<PreparedJwsObject>
|
|
17
25
|
|
|
@@ -21,11 +29,15 @@ export interface IJwtService extends IPluginMethodMap {
|
|
|
21
29
|
|
|
22
30
|
jwtCreateJwsCompactSignature(args: CreateJwsCompactArgs, context: IRequiredContext): Promise<JwsCompactResult>
|
|
23
31
|
|
|
24
|
-
|
|
32
|
+
jwtVerifyJwsSignature(args: VerifyJwsArgs, context: IRequiredContext): Promise<IJwsValidationResult>
|
|
25
33
|
|
|
26
34
|
// TODO: JWE/encryption
|
|
27
35
|
}
|
|
28
36
|
|
|
37
|
+
export type IJwsValidationResult = IValidationResult & {
|
|
38
|
+
jws: JwsJsonGeneralWithIdentifiers // We always translate to general as that is the most flexible format allowing multiple sigs
|
|
39
|
+
}
|
|
40
|
+
|
|
29
41
|
export interface PreparedJws {
|
|
30
42
|
protectedHeader: JwtHeader
|
|
31
43
|
payload: Uint8Array
|
|
@@ -39,6 +51,8 @@ export interface JwsJsonSignature {
|
|
|
39
51
|
signature: string
|
|
40
52
|
}
|
|
41
53
|
|
|
54
|
+
export type Jws = JwsCompact | JwsJsonFlattened | JwsJsonGeneral
|
|
55
|
+
|
|
42
56
|
export type JwsCompact = string
|
|
43
57
|
|
|
44
58
|
export interface JwsJsonFlattened {
|
|
@@ -53,6 +67,14 @@ export interface JwsJsonGeneral {
|
|
|
53
67
|
signatures: Array<JwsJsonSignature>
|
|
54
68
|
}
|
|
55
69
|
|
|
70
|
+
export interface JwsJsonGeneralWithIdentifiers extends JwsJsonGeneral {
|
|
71
|
+
signatures: Array<JwsJsonSignatureWithIdentifier>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface JwsJsonSignatureWithIdentifier extends JwsJsonSignature {
|
|
75
|
+
identifier: ExternalIdentifierResult
|
|
76
|
+
}
|
|
77
|
+
|
|
56
78
|
export interface PreparedJwsObject {
|
|
57
79
|
jws: PreparedJws
|
|
58
80
|
b64: { payload: string; protectedHeader: string } // header is always json, as it can only be used in JwsJson
|
|
@@ -64,6 +86,7 @@ export interface BaseJwtHeader {
|
|
|
64
86
|
alg?: string
|
|
65
87
|
kid?: string
|
|
66
88
|
}
|
|
89
|
+
|
|
67
90
|
export interface BaseJwtPayload {
|
|
68
91
|
iss?: string
|
|
69
92
|
sub?: string
|
|
@@ -87,14 +110,19 @@ export interface JwtPayload extends BaseJwtPayload {
|
|
|
87
110
|
}
|
|
88
111
|
|
|
89
112
|
export interface JwsHeaderOpts {
|
|
90
|
-
|
|
113
|
+
alg: JoseSignatureAlgorithm | JoseSignatureAlgorithmString
|
|
91
114
|
}
|
|
92
115
|
|
|
93
|
-
export type
|
|
116
|
+
export type JwsIdentifierMode = 'x5c' | 'kid' | 'jwk' | 'did' | 'auto'
|
|
94
117
|
|
|
95
118
|
export type CreateJwsArgs = {
|
|
96
|
-
mode?:
|
|
97
|
-
issuer: ManagedIdentifierOptsOrResult & {
|
|
119
|
+
mode?: JwsIdentifierMode
|
|
120
|
+
issuer: ManagedIdentifierOptsOrResult & {
|
|
121
|
+
noIssPayloadUpdate?: boolean
|
|
122
|
+
noIdentifierInHeader?: boolean
|
|
123
|
+
}
|
|
124
|
+
clientId?: string
|
|
125
|
+
clientIdScheme?: ClientIdScheme | 'did' | string
|
|
98
126
|
protectedHeader: JwtHeader
|
|
99
127
|
payload: JwtPayload | Uint8Array | string
|
|
100
128
|
}
|
|
@@ -103,6 +131,12 @@ export type CreateJwsCompactArgs = CreateJwsArgs
|
|
|
103
131
|
|
|
104
132
|
export type CreateJwsFlattenedArgs = Exclude<CreateJwsJsonArgs, 'existingSignatures'>
|
|
105
133
|
|
|
134
|
+
export type VerifyJwsArgs = {
|
|
135
|
+
jws: Jws
|
|
136
|
+
jwk?: JWK // Jwk will be resolved from jws, but you can also provide one
|
|
137
|
+
opts?: { x5c?: Omit<ExternalIdentifierX5cOpts, 'identifier'>; did?: Omit<ExternalIdentifierDidOpts, 'identifier'> }
|
|
138
|
+
}
|
|
139
|
+
|
|
106
140
|
/**
|
|
107
141
|
* @public
|
|
108
142
|
*/
|
|
@@ -118,4 +152,16 @@ export interface JwsCompactResult {
|
|
|
118
152
|
jwt: JwsCompact
|
|
119
153
|
}
|
|
120
154
|
|
|
121
|
-
|
|
155
|
+
export function isJwsCompact(jws: Jws): jws is JwsCompact {
|
|
156
|
+
return typeof jws === 'string' && jws.split('~')[0].match(COMPACT_JWS_REGEX) !== null
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function isJwsJsonFlattened(jws: Jws): jws is JwsJsonFlattened {
|
|
160
|
+
return typeof jws === 'object' && 'signature' in jws && 'protected' in jws
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function isJwsJsonGeneral(jws: Jws): jws is JwsJsonGeneral {
|
|
164
|
+
return typeof jws === 'object' && 'signatures' in jws
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export const COMPACT_JWS_REGEX = /^([a-zA-Z0-9_=-]+)\.([a-zA-Z0-9_=-]+)?\.([a-zA-Z0-9_=-]+)$/
|