@sd-jwt/core 0.3.0 → 2.0.4-next.58
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/LICENSE +201 -0
- package/dist/index.d.mts +106 -0
- package/dist/index.d.ts +106 -0
- package/dist/index.js +606 -0
- package/dist/index.mjs +586 -0
- package/package.json +60 -48
- package/src/decoy.ts +15 -0
- package/src/index.ts +235 -0
- package/src/jwt.ts +107 -0
- package/src/kbjwt.ts +45 -0
- package/src/sdjwt.ts +318 -0
- package/src/test/decoy.spec.ts +30 -0
- package/src/test/index.spec.ts +379 -0
- package/src/test/jwt.spec.ts +141 -0
- package/src/test/kbjwt.spec.ts +275 -0
- package/src/test/pass.spec.ts +6 -0
- package/src/test/sdjwt.spec.ts +382 -0
- package/test/app-e2e.spec.ts +248 -0
- package/test/array_data_types.json +29 -0
- package/test/array_full_sd.json +21 -0
- package/test/array_in_sd.json +13 -0
- package/test/array_nested_in_plain.json +20 -0
- package/test/array_none_disclosed.json +17 -0
- package/test/array_of_nulls.json +15 -0
- package/test/array_of_objects.json +58 -0
- package/test/array_of_scalars.json +15 -0
- package/test/array_recursive_sd.json +35 -0
- package/test/array_recursive_sd_some_disclosed.json +55 -0
- package/test/complex.json +43 -0
- package/test/header_mod.json +44 -0
- package/test/json_serialization.json +44 -0
- package/test/key_binding.json +44 -0
- package/test/no_sd.json +36 -0
- package/test/object_data_types.json +60 -0
- package/test/recursions.json +98 -0
- package/tsconfig.json +7 -0
- package/vitest.config.mts +4 -0
- package/README.md +0 -97
- package/build/index.d.ts +0 -13
- package/build/index.js +0 -20
- package/build/index.js.map +0 -1
- package/build/jwt/error.d.ts +0 -2
- package/build/jwt/error.js +0 -7
- package/build/jwt/error.js.map +0 -1
- package/build/jwt/index.d.ts +0 -2
- package/build/jwt/index.js +0 -19
- package/build/jwt/index.js.map +0 -1
- package/build/jwt/jwt.d.ts +0 -208
- package/build/jwt/jwt.js +0 -325
- package/build/jwt/jwt.js.map +0 -1
- package/build/keyBinding/index.d.ts +0 -1
- package/build/keyBinding/index.js +0 -18
- package/build/keyBinding/index.js.map +0 -1
- package/build/keyBinding/keyBinding.d.ts +0 -64
- package/build/keyBinding/keyBinding.js +0 -119
- package/build/keyBinding/keyBinding.js.map +0 -1
- package/build/sdJwt/decoys.d.ts +0 -3
- package/build/sdJwt/decoys.js +0 -35
- package/build/sdJwt/decoys.js.map +0 -1
- package/build/sdJwt/disclosureFrame.d.ts +0 -8
- package/build/sdJwt/disclosureFrame.js +0 -87
- package/build/sdJwt/disclosureFrame.js.map +0 -1
- package/build/sdJwt/disclosures.d.ts +0 -33
- package/build/sdJwt/disclosures.js +0 -114
- package/build/sdJwt/disclosures.js.map +0 -1
- package/build/sdJwt/error.d.ts +0 -2
- package/build/sdJwt/error.js +0 -7
- package/build/sdJwt/error.js.map +0 -1
- package/build/sdJwt/index.d.ts +0 -6
- package/build/sdJwt/index.js +0 -23
- package/build/sdJwt/index.js.map +0 -1
- package/build/sdJwt/sdJwt.d.ts +0 -206
- package/build/sdJwt/sdJwt.js +0 -442
- package/build/sdJwt/sdJwt.js.map +0 -1
- package/build/sdJwt/types.d.ts +0 -5
- package/build/sdJwt/types.js +0 -3
- package/build/sdJwt/types.js.map +0 -1
- package/build/sdJwtVc/error.d.ts +0 -2
- package/build/sdJwtVc/error.js +0 -7
- package/build/sdJwtVc/error.js.map +0 -1
- package/build/sdJwtVc/index.d.ts +0 -2
- package/build/sdJwtVc/index.js +0 -19
- package/build/sdJwtVc/index.js.map +0 -1
- package/build/sdJwtVc/sdJwtVc.d.ts +0 -47
- package/build/sdJwtVc/sdJwtVc.js +0 -149
- package/build/sdJwtVc/sdJwtVc.js.map +0 -1
- package/build/signatureAndEncryptionAlgorithm.d.ts +0 -105
- package/build/signatureAndEncryptionAlgorithm.js +0 -110
- package/build/signatureAndEncryptionAlgorithm.js.map +0 -1
- package/build/types/disclosure.d.ts +0 -5
- package/build/types/disclosure.js +0 -3
- package/build/types/disclosure.js.map +0 -1
- package/build/types/index.d.ts +0 -5
- package/build/types/index.js +0 -22
- package/build/types/index.js.map +0 -1
- package/build/types/saltGenerator.d.ts +0 -17
- package/build/types/saltGenerator.js +0 -3
- package/build/types/saltGenerator.js.map +0 -1
- package/build/types/signer.d.ts +0 -2
- package/build/types/signer.js +0 -3
- package/build/types/signer.js.map +0 -1
- package/build/types/utils.d.ts +0 -2
- package/build/types/utils.js +0 -3
- package/build/types/utils.js.map +0 -1
- package/build/types/verifier.d.ts +0 -14
- package/build/types/verifier.js +0 -3
- package/build/types/verifier.js.map +0 -1
package/src/decoy.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { HasherAndAlg, SaltGenerator } from '@sd-jwt/types';
|
|
2
|
+
import { Uint8ArrayToBase64Url } from '@sd-jwt/utils';
|
|
3
|
+
|
|
4
|
+
// This function creates a decoy value that can be used to obscure SD JWT payload.
|
|
5
|
+
// The value is basically a hash of a random salt. So the value is not predictable.
|
|
6
|
+
// return value is a base64url encoded string.
|
|
7
|
+
export const createDecoy = async (
|
|
8
|
+
hash: HasherAndAlg,
|
|
9
|
+
saltGenerator: SaltGenerator,
|
|
10
|
+
): Promise<string> => {
|
|
11
|
+
const { hasher, alg } = hash;
|
|
12
|
+
const salt = await saltGenerator(16);
|
|
13
|
+
const decoy = await hasher(salt, alg);
|
|
14
|
+
return Uint8ArrayToBase64Url(decoy);
|
|
15
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { SDJWTException } from '@sd-jwt/utils';
|
|
2
|
+
import { Jwt } from './jwt';
|
|
3
|
+
import { KBJwt } from './kbjwt';
|
|
4
|
+
import { SDJwt, pack } from './sdjwt';
|
|
5
|
+
import {
|
|
6
|
+
DisclosureFrame,
|
|
7
|
+
KBOptions,
|
|
8
|
+
KB_JWT_TYP,
|
|
9
|
+
SDJWTCompact,
|
|
10
|
+
SDJWTConfig,
|
|
11
|
+
SD_JWT_TYP,
|
|
12
|
+
} from '@sd-jwt/types';
|
|
13
|
+
|
|
14
|
+
export * from './sdjwt';
|
|
15
|
+
export * from './kbjwt';
|
|
16
|
+
export * from './jwt';
|
|
17
|
+
export * from './decoy';
|
|
18
|
+
|
|
19
|
+
export class SDJwtInstance {
|
|
20
|
+
public static DEFAULT_hashAlg = 'sha-256';
|
|
21
|
+
|
|
22
|
+
private userConfig: SDJWTConfig = {};
|
|
23
|
+
|
|
24
|
+
constructor(userConfig?: SDJWTConfig) {
|
|
25
|
+
if (userConfig) {
|
|
26
|
+
this.userConfig = userConfig;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private async createKBJwt(options: KBOptions): Promise<KBJwt> {
|
|
31
|
+
if (!this.userConfig.kbSigner) {
|
|
32
|
+
throw new SDJWTException('Key Binding Signer not found');
|
|
33
|
+
}
|
|
34
|
+
if (!this.userConfig.kbSignAlg) {
|
|
35
|
+
throw new SDJWTException('Key Binding sign algorithm not specified');
|
|
36
|
+
}
|
|
37
|
+
const { payload } = options;
|
|
38
|
+
const kbJwt = new KBJwt({
|
|
39
|
+
header: {
|
|
40
|
+
typ: KB_JWT_TYP,
|
|
41
|
+
alg: this.userConfig.kbSignAlg,
|
|
42
|
+
},
|
|
43
|
+
payload,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await kbJwt.sign(this.userConfig.kbSigner);
|
|
47
|
+
return kbJwt;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private async SignJwt(jwt: Jwt) {
|
|
51
|
+
if (!this.userConfig.signer) {
|
|
52
|
+
throw new SDJWTException('Signer not found');
|
|
53
|
+
}
|
|
54
|
+
await jwt.sign(this.userConfig.signer);
|
|
55
|
+
return jwt;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private async VerifyJwt(jwt: Jwt) {
|
|
59
|
+
if (!this.userConfig.verifier) {
|
|
60
|
+
throw new SDJWTException('Verifier not found');
|
|
61
|
+
}
|
|
62
|
+
return jwt.verify(this.userConfig.verifier);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async issue<Payload extends Record<string, unknown>>(
|
|
66
|
+
payload: Payload,
|
|
67
|
+
disclosureFrame?: DisclosureFrame<Payload>,
|
|
68
|
+
options?: {
|
|
69
|
+
header?: object; // This is for customizing the header of the jwt
|
|
70
|
+
},
|
|
71
|
+
): Promise<SDJWTCompact> {
|
|
72
|
+
if (!this.userConfig.hasher) {
|
|
73
|
+
throw new SDJWTException('Hasher not found');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!this.userConfig.saltGenerator) {
|
|
77
|
+
throw new SDJWTException('SaltGenerator not found');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!this.userConfig.signAlg) {
|
|
81
|
+
throw new SDJWTException('sign alogrithm not specified');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const hasher = this.userConfig.hasher;
|
|
85
|
+
const hashAlg = this.userConfig.hashAlg ?? SDJwtInstance.DEFAULT_hashAlg;
|
|
86
|
+
|
|
87
|
+
const { packedClaims, disclosures } = await pack(
|
|
88
|
+
payload,
|
|
89
|
+
disclosureFrame,
|
|
90
|
+
{ hasher, alg: hashAlg },
|
|
91
|
+
this.userConfig.saltGenerator,
|
|
92
|
+
);
|
|
93
|
+
const alg = this.userConfig.signAlg;
|
|
94
|
+
const OptionHeader = options?.header ?? {};
|
|
95
|
+
const CustomHeader = this.userConfig.omitTyp
|
|
96
|
+
? OptionHeader
|
|
97
|
+
: { typ: SD_JWT_TYP, ...OptionHeader };
|
|
98
|
+
const header = { ...CustomHeader, alg };
|
|
99
|
+
const jwt = new Jwt({
|
|
100
|
+
header,
|
|
101
|
+
payload: {
|
|
102
|
+
...packedClaims,
|
|
103
|
+
_sd_alg: hashAlg,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
await this.SignJwt(jwt);
|
|
107
|
+
|
|
108
|
+
const sdJwt = new SDJwt({
|
|
109
|
+
jwt,
|
|
110
|
+
disclosures,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return sdJwt.encodeSDJwt();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public async present(
|
|
117
|
+
encodedSDJwt: string,
|
|
118
|
+
presentationKeys?: string[],
|
|
119
|
+
options?: {
|
|
120
|
+
kb?: KBOptions;
|
|
121
|
+
},
|
|
122
|
+
): Promise<SDJWTCompact> {
|
|
123
|
+
if (!presentationKeys) return encodedSDJwt;
|
|
124
|
+
if (!this.userConfig.hasher) {
|
|
125
|
+
throw new SDJWTException('Hasher not found');
|
|
126
|
+
}
|
|
127
|
+
const hasher = this.userConfig.hasher;
|
|
128
|
+
|
|
129
|
+
const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
130
|
+
const kbJwt = options?.kb ? await this.createKBJwt(options.kb) : undefined;
|
|
131
|
+
sdjwt.kbJwt = kbJwt;
|
|
132
|
+
|
|
133
|
+
return sdjwt.present(presentationKeys.sort(), hasher);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// This function is for verifying the SD JWT
|
|
137
|
+
// If requiredClaimKeys is provided, it will check if the required claim keys are presentation in the SD JWT
|
|
138
|
+
// If requireKeyBindings is true, it will check if the key binding JWT is presentation and verify it
|
|
139
|
+
public async verify(
|
|
140
|
+
encodedSDJwt: string,
|
|
141
|
+
requiredClaimKeys?: string[],
|
|
142
|
+
requireKeyBindings?: boolean,
|
|
143
|
+
) {
|
|
144
|
+
if (!this.userConfig.hasher) {
|
|
145
|
+
throw new SDJWTException('Hasher not found');
|
|
146
|
+
}
|
|
147
|
+
const hasher = this.userConfig.hasher;
|
|
148
|
+
|
|
149
|
+
const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
150
|
+
if (!sdjwt.jwt) {
|
|
151
|
+
throw new SDJWTException('Invalid SD JWT');
|
|
152
|
+
}
|
|
153
|
+
const { payload, header } = await this.validate(encodedSDJwt);
|
|
154
|
+
|
|
155
|
+
if (requiredClaimKeys) {
|
|
156
|
+
const keys = await sdjwt.keys(hasher);
|
|
157
|
+
const missingKeys = requiredClaimKeys.filter((k) => !keys.includes(k));
|
|
158
|
+
if (missingKeys.length > 0) {
|
|
159
|
+
throw new SDJWTException(
|
|
160
|
+
`Missing required claim keys: ${missingKeys.join(', ')}`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!requireKeyBindings) {
|
|
166
|
+
return { payload, header };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!sdjwt.kbJwt) {
|
|
170
|
+
throw new SDJWTException('Key Binding JWT not exist');
|
|
171
|
+
}
|
|
172
|
+
if (!this.userConfig.kbVerifier) {
|
|
173
|
+
throw new SDJWTException('Key Binding Verifier not found');
|
|
174
|
+
}
|
|
175
|
+
const kb = await sdjwt.kbJwt.verify(this.userConfig.kbVerifier);
|
|
176
|
+
return { payload, header, kb };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// This function is for validating the SD JWT
|
|
180
|
+
// Just checking signature and return its the claims
|
|
181
|
+
public async validate(encodedSDJwt: string) {
|
|
182
|
+
if (!this.userConfig.hasher) {
|
|
183
|
+
throw new SDJWTException('Hasher not found');
|
|
184
|
+
}
|
|
185
|
+
const hasher = this.userConfig.hasher;
|
|
186
|
+
|
|
187
|
+
const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
188
|
+
if (!sdjwt.jwt) {
|
|
189
|
+
throw new SDJWTException('Invalid SD JWT');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const verifiedPayloads = await this.VerifyJwt(sdjwt.jwt);
|
|
193
|
+
const claims = await sdjwt.getClaims(hasher);
|
|
194
|
+
return { payload: claims, header: verifiedPayloads.header };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public config(newConfig: SDJWTConfig) {
|
|
198
|
+
this.userConfig = { ...this.userConfig, ...newConfig };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
public encode(sdJwt: SDJwt): SDJWTCompact {
|
|
202
|
+
return sdJwt.encodeSDJwt();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
public decode(endcodedSDJwt: SDJWTCompact) {
|
|
206
|
+
if (!this.userConfig.hasher) {
|
|
207
|
+
throw new SDJWTException('Hasher not found');
|
|
208
|
+
}
|
|
209
|
+
return SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
public async keys(endcodedSDJwt: SDJWTCompact) {
|
|
213
|
+
if (!this.userConfig.hasher) {
|
|
214
|
+
throw new SDJWTException('Hasher not found');
|
|
215
|
+
}
|
|
216
|
+
const sdjwt = await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
217
|
+
return sdjwt.keys(this.userConfig.hasher);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public async presentableKeys(endcodedSDJwt: SDJWTCompact) {
|
|
221
|
+
if (!this.userConfig.hasher) {
|
|
222
|
+
throw new SDJWTException('Hasher not found');
|
|
223
|
+
}
|
|
224
|
+
const sdjwt = await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
225
|
+
return sdjwt.presentableKeys(this.userConfig.hasher);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
public async getClaims(endcodedSDJwt: SDJWTCompact) {
|
|
229
|
+
if (!this.userConfig.hasher) {
|
|
230
|
+
throw new SDJWTException('Hasher not found');
|
|
231
|
+
}
|
|
232
|
+
const sdjwt = await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
233
|
+
return sdjwt.getClaims(this.userConfig.hasher);
|
|
234
|
+
}
|
|
235
|
+
}
|
package/src/jwt.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Base64urlEncode, SDJWTException } from '@sd-jwt/utils';
|
|
2
|
+
import { Base64urlString, Signer, Verifier } from '@sd-jwt/types';
|
|
3
|
+
import { decodeJwt } from '@sd-jwt/decode';
|
|
4
|
+
|
|
5
|
+
export type JwtData<
|
|
6
|
+
Header extends Record<string, unknown>,
|
|
7
|
+
Payload extends Record<string, unknown>,
|
|
8
|
+
> = {
|
|
9
|
+
header?: Header;
|
|
10
|
+
payload?: Payload;
|
|
11
|
+
signature?: Base64urlString;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// This class is used to create and verify JWT
|
|
15
|
+
// Contains header, payload, and signature
|
|
16
|
+
export class Jwt<
|
|
17
|
+
Header extends Record<string, unknown> = Record<string, unknown>,
|
|
18
|
+
Payload extends Record<string, unknown> = Record<string, unknown>,
|
|
19
|
+
> {
|
|
20
|
+
public header?: Header;
|
|
21
|
+
public payload?: Payload;
|
|
22
|
+
public signature?: Base64urlString;
|
|
23
|
+
|
|
24
|
+
constructor(data?: JwtData<Header, Payload>) {
|
|
25
|
+
this.header = data?.header;
|
|
26
|
+
this.payload = data?.payload;
|
|
27
|
+
this.signature = data?.signature;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static decodeJWT<
|
|
31
|
+
Header extends Record<string, unknown> = Record<string, unknown>,
|
|
32
|
+
Payload extends Record<string, unknown> = Record<string, unknown>,
|
|
33
|
+
>(
|
|
34
|
+
jwt: string,
|
|
35
|
+
): { header: Header; payload: Payload; signature: Base64urlString } {
|
|
36
|
+
return decodeJwt(jwt);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public static fromEncode<
|
|
40
|
+
Header extends Record<string, unknown> = Record<string, unknown>,
|
|
41
|
+
Payload extends Record<string, unknown> = Record<string, unknown>,
|
|
42
|
+
>(encodedJwt: string): Jwt<Header, Payload> {
|
|
43
|
+
const { header, payload, signature } = Jwt.decodeJWT<Header, Payload>(
|
|
44
|
+
encodedJwt,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const jwt = new Jwt<Header, Payload>({
|
|
48
|
+
header,
|
|
49
|
+
payload,
|
|
50
|
+
signature,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return jwt;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public setHeader(header: Header): Jwt<Header, Payload> {
|
|
57
|
+
this.header = header;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public setPayload(payload: Payload): Jwt<Header, Payload> {
|
|
62
|
+
this.payload = payload;
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public async sign(signer: Signer) {
|
|
67
|
+
if (!this.header || !this.payload) {
|
|
68
|
+
throw new SDJWTException('Sign Error: Invalid JWT');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const header = Base64urlEncode(JSON.stringify(this.header));
|
|
72
|
+
const payload = Base64urlEncode(JSON.stringify(this.payload));
|
|
73
|
+
const data = `${header}.${payload}`;
|
|
74
|
+
this.signature = await signer(data);
|
|
75
|
+
|
|
76
|
+
return this.encodeJwt();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public encodeJwt(): string {
|
|
80
|
+
if (!this.header || !this.payload || !this.signature) {
|
|
81
|
+
throw new SDJWTException('Serialize Error: Invalid JWT');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const header = Base64urlEncode(JSON.stringify(this.header));
|
|
85
|
+
const payload = Base64urlEncode(JSON.stringify(this.payload));
|
|
86
|
+
const signature = this.signature;
|
|
87
|
+
const compact = `${header}.${payload}.${signature}`;
|
|
88
|
+
|
|
89
|
+
return compact;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public async verify(verifier: Verifier) {
|
|
93
|
+
if (!this.header || !this.payload || !this.signature) {
|
|
94
|
+
throw new SDJWTException('Verify Error: Invalid JWT');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const header = Base64urlEncode(JSON.stringify(this.header));
|
|
98
|
+
const payload = Base64urlEncode(JSON.stringify(this.payload));
|
|
99
|
+
const data = `${header}.${payload}`;
|
|
100
|
+
|
|
101
|
+
const verified = verifier(data, this.signature);
|
|
102
|
+
if (!verified) {
|
|
103
|
+
throw new SDJWTException('Verify Error: Invalid JWT Signature');
|
|
104
|
+
}
|
|
105
|
+
return { payload: this.payload, header: this.header };
|
|
106
|
+
}
|
|
107
|
+
}
|
package/src/kbjwt.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { SDJWTException } from '@sd-jwt/utils';
|
|
2
|
+
import { Jwt } from './jwt';
|
|
3
|
+
import { Verifier, kbHeader, kbPayload } from '@sd-jwt/types';
|
|
4
|
+
|
|
5
|
+
export class KBJwt<
|
|
6
|
+
Header extends kbHeader = kbHeader,
|
|
7
|
+
Payload extends kbPayload = kbPayload,
|
|
8
|
+
> extends Jwt<Header, Payload> {
|
|
9
|
+
// Checking the validity of the key binding jwt
|
|
10
|
+
public async verify(verifier: Verifier) {
|
|
11
|
+
if (
|
|
12
|
+
!this.header?.alg ||
|
|
13
|
+
!this.header.typ ||
|
|
14
|
+
!this.payload?.iat ||
|
|
15
|
+
!this.payload?.aud ||
|
|
16
|
+
!this.payload?.nonce ||
|
|
17
|
+
// this is for backward compatibility with version 06
|
|
18
|
+
!(
|
|
19
|
+
this.payload?.sd_hash ||
|
|
20
|
+
(this.payload as Record<string, unknown> | undefined)?._sd_hash
|
|
21
|
+
)
|
|
22
|
+
) {
|
|
23
|
+
throw new SDJWTException('Invalid Key Binding Jwt');
|
|
24
|
+
}
|
|
25
|
+
return await super.verify(verifier);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// This function is for creating KBJwt object for verify properly
|
|
29
|
+
public static fromKBEncode<
|
|
30
|
+
Header extends kbHeader = kbHeader,
|
|
31
|
+
Payload extends kbPayload = kbPayload,
|
|
32
|
+
>(encodedJwt: string): KBJwt<Header, Payload> {
|
|
33
|
+
const { header, payload, signature } = Jwt.decodeJWT<Header, Payload>(
|
|
34
|
+
encodedJwt,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const jwt = new KBJwt<Header, Payload>({
|
|
38
|
+
header,
|
|
39
|
+
payload,
|
|
40
|
+
signature,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return jwt;
|
|
44
|
+
}
|
|
45
|
+
}
|