@sd-jwt/core 0.4.1-next.9 → 0.5.0

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/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.5.0](https://github.com/openwallet-foundation-labs/sd-jwt-js/compare/v0.4.0...v0.5.0) (2024-03-11)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * validate JWT signed other implemenation ([#158](https://github.com/openwallet-foundation-labs/sd-jwt-js/issues/158)) ([a0c1ddb](https://github.com/openwallet-foundation-labs/sd-jwt-js/commit/a0c1ddbb4c3785d03fc7302183f9c13e3c3fd955))
12
+
13
+
14
+ ### Features
15
+
16
+ * make _digest value public in disclosure ([#151](https://github.com/openwallet-foundation-labs/sd-jwt-js/issues/151)) ([7a3fbd7](https://github.com/openwallet-foundation-labs/sd-jwt-js/commit/7a3fbd7db19b6501978340c972b171743d287285))
17
+
18
+
19
+
20
+
21
+
6
22
  # 0.4.0 (2024-03-08)
7
23
 
8
24
 
package/dist/index.d.mts CHANGED
@@ -6,11 +6,13 @@ type JwtData<Header extends Record<string, unknown>, Payload extends Record<stri
6
6
  header?: Header;
7
7
  payload?: Payload;
8
8
  signature?: Base64urlString;
9
+ encoded?: string;
9
10
  };
10
11
  declare class Jwt<Header extends Record<string, unknown> = Record<string, unknown>, Payload extends Record<string, unknown> = Record<string, unknown>> {
11
12
  header?: Header;
12
13
  payload?: Payload;
13
14
  signature?: Base64urlString;
15
+ private encoded?;
14
16
  constructor(data?: JwtData<Header, Payload>);
15
17
  static decodeJWT<Header extends Record<string, unknown> = Record<string, unknown>, Payload extends Record<string, unknown> = Record<string, unknown>>(jwt: string): {
16
18
  header: Header;
@@ -20,11 +22,12 @@ declare class Jwt<Header extends Record<string, unknown> = Record<string, unknow
20
22
  static fromEncode<Header extends Record<string, unknown> = Record<string, unknown>, Payload extends Record<string, unknown> = Record<string, unknown>>(encodedJwt: string): Jwt<Header, Payload>;
21
23
  setHeader(header: Header): Jwt<Header, Payload>;
22
24
  setPayload(payload: Payload): Jwt<Header, Payload>;
25
+ protected getUnsignedToken(): string;
23
26
  sign(signer: Signer): Promise<string>;
24
27
  encodeJwt(): string;
25
28
  verify(verifier: Verifier): Promise<{
26
- payload: Payload;
27
- header: Header;
29
+ payload: Payload | undefined;
30
+ header: Header | undefined;
28
31
  }>;
29
32
  }
30
33
 
@@ -92,11 +95,11 @@ declare class SDJwtInstance<ExtendedPayload extends SdJwtPayload> {
92
95
  }): Promise<SDJWTCompact>;
93
96
  verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean): Promise<{
94
97
  payload: unknown;
95
- header: Record<string, unknown>;
98
+ header: Record<string, unknown> | undefined;
96
99
  kb?: undefined;
97
100
  } | {
98
101
  payload: unknown;
99
- header: Record<string, unknown>;
102
+ header: Record<string, unknown> | undefined;
100
103
  kb: {
101
104
  payload: _sd_jwt_types.kbPayload;
102
105
  header: _sd_jwt_types.kbHeader;
@@ -105,7 +108,7 @@ declare class SDJwtInstance<ExtendedPayload extends SdJwtPayload> {
105
108
  private calculateSDHash;
106
109
  validate(encodedSDJwt: string): Promise<{
107
110
  payload: unknown;
108
- header: Record<string, unknown>;
111
+ header: Record<string, unknown> | undefined;
109
112
  }>;
110
113
  config(newConfig: SDJWTConfig): void;
111
114
  encode(sdJwt: SDJwt): SDJWTCompact;
package/dist/index.d.ts CHANGED
@@ -6,11 +6,13 @@ type JwtData<Header extends Record<string, unknown>, Payload extends Record<stri
6
6
  header?: Header;
7
7
  payload?: Payload;
8
8
  signature?: Base64urlString;
9
+ encoded?: string;
9
10
  };
10
11
  declare class Jwt<Header extends Record<string, unknown> = Record<string, unknown>, Payload extends Record<string, unknown> = Record<string, unknown>> {
11
12
  header?: Header;
12
13
  payload?: Payload;
13
14
  signature?: Base64urlString;
15
+ private encoded?;
14
16
  constructor(data?: JwtData<Header, Payload>);
15
17
  static decodeJWT<Header extends Record<string, unknown> = Record<string, unknown>, Payload extends Record<string, unknown> = Record<string, unknown>>(jwt: string): {
16
18
  header: Header;
@@ -20,11 +22,12 @@ declare class Jwt<Header extends Record<string, unknown> = Record<string, unknow
20
22
  static fromEncode<Header extends Record<string, unknown> = Record<string, unknown>, Payload extends Record<string, unknown> = Record<string, unknown>>(encodedJwt: string): Jwt<Header, Payload>;
21
23
  setHeader(header: Header): Jwt<Header, Payload>;
22
24
  setPayload(payload: Payload): Jwt<Header, Payload>;
25
+ protected getUnsignedToken(): string;
23
26
  sign(signer: Signer): Promise<string>;
24
27
  encodeJwt(): string;
25
28
  verify(verifier: Verifier): Promise<{
26
- payload: Payload;
27
- header: Header;
29
+ payload: Payload | undefined;
30
+ header: Header | undefined;
28
31
  }>;
29
32
  }
30
33
 
@@ -92,11 +95,11 @@ declare class SDJwtInstance<ExtendedPayload extends SdJwtPayload> {
92
95
  }): Promise<SDJWTCompact>;
93
96
  verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean): Promise<{
94
97
  payload: unknown;
95
- header: Record<string, unknown>;
98
+ header: Record<string, unknown> | undefined;
96
99
  kb?: undefined;
97
100
  } | {
98
101
  payload: unknown;
99
- header: Record<string, unknown>;
102
+ header: Record<string, unknown> | undefined;
100
103
  kb: {
101
104
  payload: _sd_jwt_types.kbPayload;
102
105
  header: _sd_jwt_types.kbHeader;
@@ -105,7 +108,7 @@ declare class SDJwtInstance<ExtendedPayload extends SdJwtPayload> {
105
108
  private calculateSDHash;
106
109
  validate(encodedSDJwt: string): Promise<{
107
110
  payload: unknown;
108
- header: Record<string, unknown>;
111
+ header: Record<string, unknown> | undefined;
109
112
  }>;
110
113
  config(newConfig: SDJWTConfig): void;
111
114
  encode(sdJwt: SDJwt): SDJWTCompact;
package/dist/index.js CHANGED
@@ -76,6 +76,7 @@ var Jwt = class _Jwt {
76
76
  this.header = data == null ? void 0 : data.header;
77
77
  this.payload = data == null ? void 0 : data.payload;
78
78
  this.signature = data == null ? void 0 : data.signature;
79
+ this.encoded = data == null ? void 0 : data.encoded;
79
80
  }
80
81
  static decodeJWT(jwt) {
81
82
  return (0, import_decode.decodeJwt)(jwt);
@@ -87,31 +88,48 @@ var Jwt = class _Jwt {
87
88
  const jwt = new _Jwt({
88
89
  header,
89
90
  payload,
90
- signature
91
+ signature,
92
+ encoded: encodedJwt
91
93
  });
92
94
  return jwt;
93
95
  }
94
96
  setHeader(header) {
95
97
  this.header = header;
98
+ this.encoded = void 0;
96
99
  return this;
97
100
  }
98
101
  setPayload(payload) {
99
102
  this.payload = payload;
103
+ this.encoded = void 0;
100
104
  return this;
101
105
  }
106
+ getUnsignedToken() {
107
+ if (!this.header || !this.payload) {
108
+ throw new import_utils.SDJWTException("Serialize Error: Invalid JWT");
109
+ }
110
+ if (this.encoded) {
111
+ const parts = this.encoded.split(".");
112
+ if (parts.length !== 3) {
113
+ throw new import_utils.SDJWTException(`Invalid JWT format: ${this.encoded}`);
114
+ }
115
+ const unsignedToken = parts.slice(0, 2).join(".");
116
+ return unsignedToken;
117
+ }
118
+ const header = (0, import_utils.Base64urlEncode)(JSON.stringify(this.header));
119
+ const payload = (0, import_utils.Base64urlEncode)(JSON.stringify(this.payload));
120
+ return `${header}.${payload}`;
121
+ }
102
122
  sign(signer) {
103
123
  return __async(this, null, function* () {
104
- if (!this.header || !this.payload) {
105
- throw new import_utils.SDJWTException("Sign Error: Invalid JWT");
106
- }
107
- const header = (0, import_utils.Base64urlEncode)(JSON.stringify(this.header));
108
- const payload = (0, import_utils.Base64urlEncode)(JSON.stringify(this.payload));
109
- const data = `${header}.${payload}`;
124
+ const data = this.getUnsignedToken();
110
125
  this.signature = yield signer(data);
111
126
  return this.encodeJwt();
112
127
  });
113
128
  }
114
129
  encodeJwt() {
130
+ if (this.encoded) {
131
+ return this.encoded;
132
+ }
115
133
  if (!this.header || !this.payload || !this.signature) {
116
134
  throw new import_utils.SDJWTException("Serialize Error: Invalid JWT");
117
135
  }
@@ -119,16 +137,15 @@ var Jwt = class _Jwt {
119
137
  const payload = (0, import_utils.Base64urlEncode)(JSON.stringify(this.payload));
120
138
  const signature = this.signature;
121
139
  const compact = `${header}.${payload}.${signature}`;
140
+ this.encoded = compact;
122
141
  return compact;
123
142
  }
124
143
  verify(verifier) {
125
144
  return __async(this, null, function* () {
126
- if (!this.header || !this.payload || !this.signature) {
127
- throw new import_utils.SDJWTException("Verify Error: Invalid JWT");
145
+ if (!this.signature) {
146
+ throw new import_utils.SDJWTException("Verify Error: no signature in JWT");
128
147
  }
129
- const header = (0, import_utils.Base64urlEncode)(JSON.stringify(this.header));
130
- const payload = (0, import_utils.Base64urlEncode)(JSON.stringify(this.payload));
131
- const data = `${header}.${payload}`;
148
+ const data = this.getUnsignedToken();
132
149
  const verified = yield verifier(data, this.signature);
133
150
  if (!verified) {
134
151
  throw new import_utils.SDJWTException("Verify Error: Invalid JWT Signature");
@@ -154,9 +171,7 @@ var KBJwt = class _KBJwt extends Jwt {
154
171
  !(this.payload.sd_hash || ((_a = this.payload) == null ? void 0 : _a._sd_hash))) {
155
172
  throw new import_utils2.SDJWTException("Invalid Key Binding Jwt");
156
173
  }
157
- const header = (0, import_utils2.Base64urlEncode)(JSON.stringify(this.header));
158
- const payload = (0, import_utils2.Base64urlEncode)(JSON.stringify(this.payload));
159
- const data = `${header}.${payload}`;
174
+ const data = this.getUnsignedToken();
160
175
  const verified = yield values.verifier(
161
176
  data,
162
177
  this.signature,
@@ -176,7 +191,8 @@ var KBJwt = class _KBJwt extends Jwt {
176
191
  const jwt = new _KBJwt({
177
192
  header,
178
193
  payload,
179
- signature
194
+ signature,
195
+ encoded: encodedJwt
180
196
  });
181
197
  return jwt;
182
198
  }
package/dist/index.mjs CHANGED
@@ -49,6 +49,7 @@ var Jwt = class _Jwt {
49
49
  this.header = data == null ? void 0 : data.header;
50
50
  this.payload = data == null ? void 0 : data.payload;
51
51
  this.signature = data == null ? void 0 : data.signature;
52
+ this.encoded = data == null ? void 0 : data.encoded;
52
53
  }
53
54
  static decodeJWT(jwt) {
54
55
  return decodeJwt(jwt);
@@ -60,31 +61,48 @@ var Jwt = class _Jwt {
60
61
  const jwt = new _Jwt({
61
62
  header,
62
63
  payload,
63
- signature
64
+ signature,
65
+ encoded: encodedJwt
64
66
  });
65
67
  return jwt;
66
68
  }
67
69
  setHeader(header) {
68
70
  this.header = header;
71
+ this.encoded = void 0;
69
72
  return this;
70
73
  }
71
74
  setPayload(payload) {
72
75
  this.payload = payload;
76
+ this.encoded = void 0;
73
77
  return this;
74
78
  }
79
+ getUnsignedToken() {
80
+ if (!this.header || !this.payload) {
81
+ throw new SDJWTException("Serialize Error: Invalid JWT");
82
+ }
83
+ if (this.encoded) {
84
+ const parts = this.encoded.split(".");
85
+ if (parts.length !== 3) {
86
+ throw new SDJWTException(`Invalid JWT format: ${this.encoded}`);
87
+ }
88
+ const unsignedToken = parts.slice(0, 2).join(".");
89
+ return unsignedToken;
90
+ }
91
+ const header = Base64urlEncode(JSON.stringify(this.header));
92
+ const payload = Base64urlEncode(JSON.stringify(this.payload));
93
+ return `${header}.${payload}`;
94
+ }
75
95
  sign(signer) {
76
96
  return __async(this, null, function* () {
77
- if (!this.header || !this.payload) {
78
- throw new SDJWTException("Sign Error: Invalid JWT");
79
- }
80
- const header = Base64urlEncode(JSON.stringify(this.header));
81
- const payload = Base64urlEncode(JSON.stringify(this.payload));
82
- const data = `${header}.${payload}`;
97
+ const data = this.getUnsignedToken();
83
98
  this.signature = yield signer(data);
84
99
  return this.encodeJwt();
85
100
  });
86
101
  }
87
102
  encodeJwt() {
103
+ if (this.encoded) {
104
+ return this.encoded;
105
+ }
88
106
  if (!this.header || !this.payload || !this.signature) {
89
107
  throw new SDJWTException("Serialize Error: Invalid JWT");
90
108
  }
@@ -92,16 +110,15 @@ var Jwt = class _Jwt {
92
110
  const payload = Base64urlEncode(JSON.stringify(this.payload));
93
111
  const signature = this.signature;
94
112
  const compact = `${header}.${payload}.${signature}`;
113
+ this.encoded = compact;
95
114
  return compact;
96
115
  }
97
116
  verify(verifier) {
98
117
  return __async(this, null, function* () {
99
- if (!this.header || !this.payload || !this.signature) {
100
- throw new SDJWTException("Verify Error: Invalid JWT");
118
+ if (!this.signature) {
119
+ throw new SDJWTException("Verify Error: no signature in JWT");
101
120
  }
102
- const header = Base64urlEncode(JSON.stringify(this.header));
103
- const payload = Base64urlEncode(JSON.stringify(this.payload));
104
- const data = `${header}.${payload}`;
121
+ const data = this.getUnsignedToken();
105
122
  const verified = yield verifier(data, this.signature);
106
123
  if (!verified) {
107
124
  throw new SDJWTException("Verify Error: Invalid JWT Signature");
@@ -112,7 +129,7 @@ var Jwt = class _Jwt {
112
129
  };
113
130
 
114
131
  // src/kbjwt.ts
115
- import { Base64urlEncode as Base64urlEncode2, SDJWTException as SDJWTException2 } from "@sd-jwt/utils";
132
+ import { SDJWTException as SDJWTException2 } from "@sd-jwt/utils";
116
133
  import {
117
134
  KB_JWT_TYP
118
135
  } from "@sd-jwt/types";
@@ -129,9 +146,7 @@ var KBJwt = class _KBJwt extends Jwt {
129
146
  !(this.payload.sd_hash || ((_a = this.payload) == null ? void 0 : _a._sd_hash))) {
130
147
  throw new SDJWTException2("Invalid Key Binding Jwt");
131
148
  }
132
- const header = Base64urlEncode2(JSON.stringify(this.header));
133
- const payload = Base64urlEncode2(JSON.stringify(this.payload));
134
- const data = `${header}.${payload}`;
149
+ const data = this.getUnsignedToken();
135
150
  const verified = yield values.verifier(
136
151
  data,
137
152
  this.signature,
@@ -151,7 +166,8 @@ var KBJwt = class _KBJwt extends Jwt {
151
166
  const jwt = new _KBJwt({
152
167
  header,
153
168
  payload,
154
- signature
169
+ signature,
170
+ encoded: encodedJwt
155
171
  });
156
172
  return jwt;
157
173
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sd-jwt/core",
3
- "version": "0.4.1-next.9+9231fe0",
3
+ "version": "0.5.0",
4
4
  "description": "sd-jwt draft 7 implementation in typescript",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -38,13 +38,13 @@
38
38
  },
39
39
  "license": "Apache-2.0",
40
40
  "devDependencies": {
41
- "@sd-jwt/crypto-nodejs": "0.4.1-next.9+9231fe0"
41
+ "@sd-jwt/crypto-nodejs": "0.5.0"
42
42
  },
43
43
  "dependencies": {
44
- "@sd-jwt/decode": "0.4.1-next.9+9231fe0",
45
- "@sd-jwt/present": "0.4.1-next.9+9231fe0",
46
- "@sd-jwt/types": "0.4.1-next.9+9231fe0",
47
- "@sd-jwt/utils": "0.4.1-next.9+9231fe0"
44
+ "@sd-jwt/decode": "0.5.0",
45
+ "@sd-jwt/present": "0.5.0",
46
+ "@sd-jwt/types": "0.5.0",
47
+ "@sd-jwt/utils": "0.5.0"
48
48
  },
49
49
  "publishConfig": {
50
50
  "access": "public"
@@ -62,5 +62,5 @@
62
62
  "esm"
63
63
  ]
64
64
  },
65
- "gitHead": "9231fe047072630b85b5ce11ff66686d9e9ac70d"
65
+ "gitHead": "513e36a23c96953368c050f5b82a43da2dcace65"
66
66
  }
package/src/jwt.ts CHANGED
@@ -9,6 +9,7 @@ export type JwtData<
9
9
  header?: Header;
10
10
  payload?: Payload;
11
11
  signature?: Base64urlString;
12
+ encoded?: string;
12
13
  };
13
14
 
14
15
  // This class is used to create and verify JWT
@@ -20,11 +21,13 @@ export class Jwt<
20
21
  public header?: Header;
21
22
  public payload?: Payload;
22
23
  public signature?: Base64urlString;
24
+ private encoded?: string;
23
25
 
24
26
  constructor(data?: JwtData<Header, Payload>) {
25
27
  this.header = data?.header;
26
28
  this.payload = data?.payload;
27
29
  this.signature = data?.signature;
30
+ this.encoded = data?.encoded;
28
31
  }
29
32
 
30
33
  public static decodeJWT<
@@ -48,6 +51,7 @@ export class Jwt<
48
51
  header,
49
52
  payload,
50
53
  signature,
54
+ encoded: encodedJwt,
51
55
  });
52
56
 
53
57
  return jwt;
@@ -55,28 +59,47 @@ export class Jwt<
55
59
 
56
60
  public setHeader(header: Header): Jwt<Header, Payload> {
57
61
  this.header = header;
62
+ this.encoded = undefined;
58
63
  return this;
59
64
  }
60
65
 
61
66
  public setPayload(payload: Payload): Jwt<Header, Payload> {
62
67
  this.payload = payload;
68
+ this.encoded = undefined;
63
69
  return this;
64
70
  }
65
71
 
66
- public async sign(signer: Signer) {
72
+ protected getUnsignedToken() {
67
73
  if (!this.header || !this.payload) {
68
- throw new SDJWTException('Sign Error: Invalid JWT');
74
+ throw new SDJWTException('Serialize Error: Invalid JWT');
75
+ }
76
+
77
+ if (this.encoded) {
78
+ const parts = this.encoded.split('.');
79
+ if (parts.length !== 3) {
80
+ throw new SDJWTException(`Invalid JWT format: ${this.encoded}`);
81
+ }
82
+ const unsignedToken = parts.slice(0, 2).join('.');
83
+ return unsignedToken;
69
84
  }
70
85
 
71
86
  const header = Base64urlEncode(JSON.stringify(this.header));
72
87
  const payload = Base64urlEncode(JSON.stringify(this.payload));
73
- const data = `${header}.${payload}`;
88
+ return `${header}.${payload}`;
89
+ }
90
+
91
+ public async sign(signer: Signer) {
92
+ const data = this.getUnsignedToken();
74
93
  this.signature = await signer(data);
75
94
 
76
95
  return this.encodeJwt();
77
96
  }
78
97
 
79
98
  public encodeJwt(): string {
99
+ if (this.encoded) {
100
+ return this.encoded;
101
+ }
102
+
80
103
  if (!this.header || !this.payload || !this.signature) {
81
104
  throw new SDJWTException('Serialize Error: Invalid JWT');
82
105
  }
@@ -85,18 +108,16 @@ export class Jwt<
85
108
  const payload = Base64urlEncode(JSON.stringify(this.payload));
86
109
  const signature = this.signature;
87
110
  const compact = `${header}.${payload}.${signature}`;
111
+ this.encoded = compact;
88
112
 
89
113
  return compact;
90
114
  }
91
115
 
92
116
  public async verify(verifier: Verifier) {
93
- if (!this.header || !this.payload || !this.signature) {
94
- throw new SDJWTException('Verify Error: Invalid JWT');
117
+ if (!this.signature) {
118
+ throw new SDJWTException('Verify Error: no signature in JWT');
95
119
  }
96
-
97
- const header = Base64urlEncode(JSON.stringify(this.header));
98
- const payload = Base64urlEncode(JSON.stringify(this.payload));
99
- const data = `${header}.${payload}`;
120
+ const data = this.getUnsignedToken();
100
121
 
101
122
  const verified = await verifier(data, this.signature);
102
123
  if (!verified) {
package/src/kbjwt.ts CHANGED
@@ -36,9 +36,7 @@ export class KBJwt<
36
36
  throw new SDJWTException('Invalid Key Binding Jwt');
37
37
  }
38
38
 
39
- const header = Base64urlEncode(JSON.stringify(this.header));
40
- const payload = Base64urlEncode(JSON.stringify(this.payload));
41
- const data = `${header}.${payload}`;
39
+ const data = this.getUnsignedToken();
42
40
  const verified = await values.verifier(
43
41
  data,
44
42
  this.signature,
@@ -63,6 +61,7 @@ export class KBJwt<
63
61
  header,
64
62
  payload,
65
63
  signature,
64
+ encoded: encodedJwt,
66
65
  });
67
66
 
68
67
  return jwt;
@@ -2,9 +2,15 @@ import { SDJwtInstance, type SdJwtPayload } from '../index';
2
2
  import type { Signer, Verifier, KbVerifier, JwtPayload } from '@sd-jwt/types';
3
3
  import Crypto, { type KeyLike } from 'node:crypto';
4
4
  import { describe, expect, test } from 'vitest';
5
- import { digest, generateSalt } from '@sd-jwt/crypto-nodejs';
5
+ import { digest, generateSalt, ES256 } from '@sd-jwt/crypto-nodejs';
6
6
  import { importJWK, exportJWK, type JWK } from 'jose';
7
7
 
8
+ // Extract the major version as a number
9
+ const nodeVersionMajor = Number.parseInt(
10
+ process.version.split('.')[0].substring(1),
11
+ 10,
12
+ );
13
+
8
14
  export const createSignerVerifier = () => {
9
15
  const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
10
16
  const signer: Signer = async (data: string) => {
@@ -590,4 +596,33 @@ describe('index', () => {
590
596
  expect(decoded.disclosures).toBeDefined();
591
597
  expect(decoded.kbJwt).toBeDefined();
592
598
  });
599
+
600
+ (nodeVersionMajor < 20 ? test.skip : test)(
601
+ 'validate sd-jwt that created in other implemenation',
602
+ async () => {
603
+ const publicKeyExampleJwt: JsonWebKey = {
604
+ kty: 'EC',
605
+ crv: 'P-256',
606
+ x: 'b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ',
607
+ y: 'Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8',
608
+ };
609
+ const kbPubkey: JsonWebKey = {
610
+ kty: 'EC',
611
+ crv: 'P-256',
612
+ x: 'TCAER19Zvu3OHF4j4W4vfSVoHIP1ILilDls7vCeGemc',
613
+ y: 'ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ',
614
+ };
615
+ const encodedJwt =
616
+ 'eyJhbGciOiAiRVMyNTYiLCAidHlwIjogInZjK3NkLWp3dCIsICJraWQiOiAiZG9jLXNpZ25lci0wNS0yNS0yMDIyIn0.eyJfc2QiOiBbIjA5dktySk1PbHlUV00wc2pwdV9wZE9CVkJRMk0xeTNLaHBINTE1blhrcFkiLCAiMnJzakdiYUMwa3k4bVQwcEpyUGlvV1RxMF9kYXcxc1g3NnBvVWxnQ3diSSIsICJFa084ZGhXMGRIRUpidlVIbEVfVkNldUM5dVJFTE9pZUxaaGg3WGJVVHRBIiwgIklsRHpJS2VpWmREd3BxcEs2WmZieXBoRnZ6NUZnbldhLXNONndxUVhDaXciLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiamRyVEU4WWNiWTRFaWZ1Z2loaUFlX0JQZWt4SlFaSUNlaVVRd1k5UXF4SSIsICJqc3U5eVZ1bHdRUWxoRmxNXzNKbHpNYVNGemdsaFFHMERwZmF5UXdMVUs0Il0sICJpc3MiOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9pc3N1ZXIiLCAiaWF0IjogMTY4MzAwMDAwMCwgImV4cCI6IDE4ODMwMDAwMDAsICJ2Y3QiOiAiaHR0cHM6Ly9jcmVkZW50aWFscy5leGFtcGxlLmNvbS9pZGVudGl0eV9jcmVkZW50aWFsIiwgIl9zZF9hbGciOiAic2hhLTI1NiIsICJjbmYiOiB7Imp3ayI6IHsia3R5IjogIkVDIiwgImNydiI6ICJQLTI1NiIsICJ4IjogIlRDQUVSMTladnUzT0hGNGo0VzR2ZlNWb0hJUDFJTGlsRGxzN3ZDZUdlbWMiLCAieSI6ICJaeGppV1diWk1RR0hWV0tWUTRoYlNJaXJzVmZ1ZWNDRTZ0NGpUOUYySFpRIn19fQ.QXgzrePAdq_WZVGCwDxP-l8h0iyckrHBNidxVqGtKJ0LMzObqgaXUD1cgGEf7d9TexPkBcgQYqjuzlfbeCxxuA~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL2V4YW1wbGUuY29tL3ZlcmlmaWVyIiwgImlhdCI6IDE3MDk5OTYxODUsICJzZF9oYXNoIjogIjc4cFFEazJOblNEM1dKQm5SN015aWpmeUVqcGJ5a01yRnlpb2ZYSjlsN0kifQ.7k4goAlxM4a3tHnvCBCe70j_I-BCwtzhBRXQNk9cWJnQWxxt2kIqCyzcwzzUc0gTwtbGWVQoeWCiL5K6y3a4VQ';
617
+
618
+ const sdjwt = new SDJwtInstance({
619
+ hasher: digest,
620
+ verifier: await ES256.getVerifier(publicKeyExampleJwt),
621
+ kbVerifier: await ES256.getVerifier(kbPubkey),
622
+ });
623
+
624
+ const decode = await sdjwt.verify(encodedJwt, undefined, true);
625
+ expect(decode).toBeDefined();
626
+ },
627
+ );
593
628
  });
@@ -138,4 +138,65 @@ describe('JWT', () => {
138
138
  expect(e).toBeInstanceOf(SDJWTException);
139
139
  }
140
140
  });
141
+
142
+ test('getUnsignedToken failed', async () => {
143
+ const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
144
+ const testSigner: Signer = async (data: string) => {
145
+ const sig = Crypto.sign(null, Buffer.from(data), privateKey);
146
+ return Buffer.from(sig).toString('base64url');
147
+ };
148
+
149
+ const jwt = new Jwt({
150
+ header: { alg: 'EdDSA' },
151
+ });
152
+
153
+ try {
154
+ await jwt.sign(testSigner);
155
+ } catch (e: unknown) {
156
+ expect(e).toBeInstanceOf(SDJWTException);
157
+ }
158
+ });
159
+
160
+ test('wrong encoded field', async () => {
161
+ const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
162
+ const testSigner: Signer = async (data: string) => {
163
+ const sig = Crypto.sign(null, Buffer.from(data), privateKey);
164
+ return Buffer.from(sig).toString('base64url');
165
+ };
166
+
167
+ const jwt = new Jwt({
168
+ header: { alg: 'EdDSA' },
169
+ payload: { foo: 'bar' },
170
+ encoded: 'asfasfafaf.dfasfafafasf', // it has to be 3 parts
171
+ });
172
+
173
+ try {
174
+ await jwt.sign(testSigner);
175
+ } catch (e: unknown) {
176
+ expect(e).toBeInstanceOf(SDJWTException);
177
+ }
178
+ });
179
+
180
+ test('verify failed no signature', async () => {
181
+ const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
182
+ const testVerifier: Verifier = async (data: string, sig: string) => {
183
+ return Crypto.verify(
184
+ null,
185
+ Buffer.from(data),
186
+ publicKey,
187
+ Buffer.from(sig, 'base64url'),
188
+ );
189
+ };
190
+
191
+ const jwt = new Jwt({
192
+ header: { alg: 'EdDSA' },
193
+ payload: { foo: 'bar' },
194
+ });
195
+
196
+ try {
197
+ await jwt.verify(testVerifier);
198
+ } catch (e: unknown) {
199
+ expect(e).toBeInstanceOf(SDJWTException);
200
+ }
201
+ });
141
202
  });
@@ -376,7 +376,9 @@ describe('SD JWT', () => {
376
376
 
377
377
  const credential = sdJwt.encodeSDJwt();
378
378
  const decoded = await SDJwt.decodeSDJwt(credential, hasher);
379
- expect(jwt).toEqual(decoded.jwt);
379
+ expect(jwt.header).toEqual(decoded.jwt.header);
380
+ expect(jwt.payload).toEqual(decoded.jwt.payload);
381
+ expect(jwt.signature).toEqual(decoded.jwt.signature);
380
382
  expect(decoded.disclosures).toEqual([]);
381
383
  });
382
384
  });