jose 5.9.6 → 5.10.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/README.md CHANGED
@@ -5,9 +5,9 @@
5
5
  ## Sponsor
6
6
 
7
7
  <picture>
8
- <source media="(prefers-color-scheme: dark)" srcset="./sponsor/Auth0byOkta_dark.png">
9
- <source media="(prefers-color-scheme: light)" srcset="./sponsor/Auth0byOkta_light.png">
10
- <img height="65" align="left" alt="Auth0 by Okta" src="./sponsor/Auth0byOkta_light.png">
8
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/panva/jose/HEAD/sponsor/Auth0byOkta_dark.png">
9
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/panva/jose/HEAD/sponsor/Auth0byOkta_light.png">
10
+ <img height="65" align="left" alt="Auth0 by Okta" src="https://raw.githubusercontent.com/panva/jose/HEAD/sponsor/Auth0byOkta_light.png">
11
11
  </picture>
12
12
 
13
13
  If you want to quickly add JWT authentication to JavaScript apps, feel free to check out Auth0's JavaScript SDK and free plan. [Create an Auth0 account; it's free!][sponsor-auth0]<br><br>
@@ -25,11 +25,13 @@ Support from the community to continue maintaining and improving this module is
25
25
  `jose` is distributed via [npmjs.com](https://www.npmjs.com/package/jose), [deno.land/x](https://deno.land/x/jose), [cdnjs.com](https://cdnjs.com/libraries/jose), [jsdelivr.com](https://www.jsdelivr.com/package/npm/jose), and [github.com](https://github.com/panva/jose).
26
26
 
27
27
  **`example`** ESM import
28
+
28
29
  ```js
29
30
  import * as jose from 'jose'
30
31
  ```
31
32
 
32
33
  **`example`** CJS require
34
+
33
35
  ```js
34
36
  const jose = require('jose')
35
37
  ```
@@ -107,6 +109,7 @@ The following are additional features and utilities provided by the `jose` modul
107
109
  The `jose` module is compatible with JavaScript runtimes that support the utilized Web API globals and standard built-in objects or are Node.js.
108
110
 
109
111
  The following runtimes are supported _(this is not an exhaustive list)_:
112
+
110
113
  - [Bun](https://github.com/panva/jose/issues/471)
111
114
  - [Browsers](https://github.com/panva/jose/issues/263)
112
115
  - [Cloudflare Workers](https://github.com/panva/jose/issues/265)
@@ -119,11 +122,11 @@ Please note that certain algorithms may not be available depending on the runtim
119
122
 
120
123
  ## Supported Versions
121
124
 
122
- | Version | Security Fixes 🔑 | Other Bug Fixes 🐞 | New Features ⭐ |
123
- | ------- | --------- | -------- | -------- |
124
- | [v5.x](https://github.com/panva/jose/tree/v5.x) | ✅ | ✅ | ✅ |
125
- | [v4.x](https://github.com/panva/jose/tree/v4.x) | ✅ | ❌ | ❌ |
126
- | [v2.x](https://github.com/panva/jose/tree/v2.x) | ✅ | ❌ | ❌ |
125
+ | Version | Security Fixes 🔑 | Other Bug Fixes 🐞 | New Features ⭐ |
126
+ | ----------------------------------------------- | ----------------- | ------------------ | --------------- |
127
+ | [v5.x](https://github.com/panva/jose/tree/v5.x) | ✅ | ✅ | ✅ |
128
+ | [v4.x](https://github.com/panva/jose/tree/v4.x) | ✅ | ❌ | ❌ |
129
+ | [v2.x](https://github.com/panva/jose/tree/v2.x) | ✅ | ❌ | ❌ |
127
130
 
128
131
  ## Specifications
129
132
 
@@ -143,7 +146,6 @@ Please note that certain algorithms may not be available depending on the runtim
143
146
 
144
147
  The algorithm implementations in `jose` have been tested using test vectors from their respective specifications as well as [RFC7520](https://www.rfc-editor.org/rfc/rfc7520).
145
148
 
146
-
147
149
  </details>
148
150
 
149
- [sponsor-auth0]: https://auth0.com/signup?utm_source=external_sites&utm_medium=panva&utm_campaign=devn_signup
151
+ [sponsor-auth0]: https://a0.to/signup/panva
@@ -54,9 +54,6 @@ class LocalJWKSet {
54
54
  if (candidate && Array.isArray(jwk.key_ops)) {
55
55
  candidate = jwk.key_ops.includes('verify');
56
56
  }
57
- if (candidate && alg === 'EdDSA') {
58
- candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
59
- }
60
57
  if (candidate) {
61
58
  switch (alg) {
62
59
  case 'ES256':
@@ -71,6 +68,12 @@ class LocalJWKSet {
71
68
  case 'ES512':
72
69
  candidate = jwk.crv === 'P-521';
73
70
  break;
71
+ case 'Ed25519':
72
+ candidate = jwk.crv === 'Ed25519';
73
+ break;
74
+ case 'EdDSA':
75
+ candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
76
+ break;
74
77
  }
75
78
  }
76
79
  return candidate;
@@ -10,7 +10,7 @@ function isCloudflareWorkers() {
10
10
  let USER_AGENT;
11
11
  if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
12
12
  const NAME = 'jose';
13
- const VERSION = 'v5.9.6';
13
+ const VERSION = 'v5.10.0';
14
14
  USER_AGENT = `${NAME}/${VERSION}`;
15
15
  }
16
16
  export const jwksCache = Symbol();
@@ -33,7 +33,7 @@ export async function importJWK(jwk, alg) {
33
33
  }
34
34
  return decodeBase64URL(jwk.k);
35
35
  case 'RSA':
36
- if (jwk.oth !== undefined) {
36
+ if ('oth' in jwk && jwk.oth !== undefined) {
37
37
  throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
38
38
  }
39
39
  case 'EC':
@@ -76,6 +76,11 @@ export function checkSigCryptoKey(key, alg, ...usages) {
76
76
  }
77
77
  break;
78
78
  }
79
+ case 'Ed25519': {
80
+ if (!isAlgorithm(key.algorithm, 'Ed25519'))
81
+ throw unusable('Ed25519');
82
+ break;
83
+ }
79
84
  case 'ES256':
80
85
  case 'ES384':
81
86
  case 'ES512': {
@@ -106,6 +106,10 @@ const genericImport = async (replace, keyFormat, pem, alg, options) => {
106
106
  keyUsages = isPublic ? [] : ['deriveBits'];
107
107
  break;
108
108
  }
109
+ case 'Ed25519':
110
+ algorithm = { name: 'Ed25519' };
111
+ keyUsages = isPublic ? ['verify'] : ['sign'];
112
+ break;
109
113
  case 'EdDSA':
110
114
  algorithm = { name: getNamedCurve(keyData) };
111
115
  keyUsages = isPublic ? ['verify'] : ['sign'];
@@ -97,6 +97,10 @@ export async function generateKeyPair(alg, options) {
97
97
  algorithm = { name: 'ECDSA', namedCurve: 'P-521' };
98
98
  keyUsages = ['sign', 'verify'];
99
99
  break;
100
+ case 'Ed25519':
101
+ algorithm = { name: 'Ed25519' };
102
+ keyUsages = ['sign', 'verify'];
103
+ break;
100
104
  case 'EdDSA': {
101
105
  keyUsages = ['sign', 'verify'];
102
106
  const crv = options?.crv ?? 'Ed25519';
@@ -61,6 +61,10 @@ function subtleMapping(jwk) {
61
61
  }
62
62
  case 'OKP': {
63
63
  switch (jwk.alg) {
64
+ case 'Ed25519':
65
+ algorithm = { name: 'Ed25519' };
66
+ keyUsages = jwk.d ? ['sign'] : ['verify'];
67
+ break;
64
68
  case 'EdDSA':
65
69
  algorithm = { name: jwk.crv };
66
70
  keyUsages = jwk.d ? ['sign'] : ['verify'];
@@ -18,6 +18,8 @@ export default function subtleDsa(alg, algorithm) {
18
18
  case 'ES384':
19
19
  case 'ES512':
20
20
  return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };
21
+ case 'Ed25519':
22
+ return { name: 'Ed25519' };
21
23
  case 'EdDSA':
22
24
  return { name: algorithm.name };
23
25
  default:
@@ -58,9 +58,6 @@ class LocalJWKSet {
58
58
  if (candidate && Array.isArray(jwk.key_ops)) {
59
59
  candidate = jwk.key_ops.includes('verify');
60
60
  }
61
- if (candidate && alg === 'EdDSA') {
62
- candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
63
- }
64
61
  if (candidate) {
65
62
  switch (alg) {
66
63
  case 'ES256':
@@ -75,6 +72,12 @@ class LocalJWKSet {
75
72
  case 'ES512':
76
73
  candidate = jwk.crv === 'P-521';
77
74
  break;
75
+ case 'Ed25519':
76
+ candidate = jwk.crv === 'Ed25519';
77
+ break;
78
+ case 'EdDSA':
79
+ candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
80
+ break;
78
81
  }
79
82
  }
80
83
  return candidate;
@@ -14,7 +14,7 @@ function isCloudflareWorkers() {
14
14
  let USER_AGENT;
15
15
  if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
16
16
  const NAME = 'jose';
17
- const VERSION = 'v5.9.6';
17
+ const VERSION = 'v5.10.0';
18
18
  USER_AGENT = `${NAME}/${VERSION}`;
19
19
  }
20
20
  exports.jwksCache = Symbol();
@@ -39,7 +39,7 @@ async function importJWK(jwk, alg) {
39
39
  }
40
40
  return (0, base64url_js_1.decode)(jwk.k);
41
41
  case 'RSA':
42
- if (jwk.oth !== undefined) {
42
+ if ('oth' in jwk && jwk.oth !== undefined) {
43
43
  throw new errors_js_1.JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
44
44
  }
45
45
  case 'EC':
@@ -80,6 +80,11 @@ function checkSigCryptoKey(key, alg, ...usages) {
80
80
  }
81
81
  break;
82
82
  }
83
+ case 'Ed25519': {
84
+ if (!isAlgorithm(key.algorithm, 'Ed25519'))
85
+ throw unusable('Ed25519');
86
+ break;
87
+ }
83
88
  case 'ES256':
84
89
  case 'ES384':
85
90
  case 'ES512': {
@@ -17,6 +17,7 @@ function dsaDigest(alg) {
17
17
  case 'RS512':
18
18
  case 'ES512':
19
19
  return 'sha512';
20
+ case 'Ed25519':
20
21
  case 'EdDSA':
21
22
  return undefined;
22
23
  default:
@@ -65,6 +65,8 @@ async function generateKeyPair(alg, options) {
65
65
  return generate('ec', { namedCurve: 'P-384' });
66
66
  case 'ES512':
67
67
  return generate('ec', { namedCurve: 'P-521' });
68
+ case 'Ed25519':
69
+ return generate('ed25519');
68
70
  case 'EdDSA': {
69
71
  switch (options?.crv) {
70
72
  case undefined:
@@ -45,6 +45,11 @@ function keyForCrypto(alg, key) {
45
45
  }
46
46
  let options;
47
47
  switch (alg) {
48
+ case 'Ed25519':
49
+ if (asymmetricKeyType !== 'ed25519') {
50
+ throw new TypeError(`Invalid key for this operation, its asymmetricKeyType must be ed25519`);
51
+ }
52
+ break;
48
53
  case 'EdDSA':
49
54
  if (!['ed25519', 'ed448'].includes(asymmetricKeyType)) {
50
55
  throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ed25519 or ed448');
@@ -55,9 +55,6 @@ class LocalJWKSet {
55
55
  if (candidate && Array.isArray(jwk.key_ops)) {
56
56
  candidate = jwk.key_ops.includes('verify');
57
57
  }
58
- if (candidate && alg === 'EdDSA') {
59
- candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
60
- }
61
58
  if (candidate) {
62
59
  switch (alg) {
63
60
  case 'ES256':
@@ -72,6 +69,12 @@ class LocalJWKSet {
72
69
  case 'ES512':
73
70
  candidate = jwk.crv === 'P-521';
74
71
  break;
72
+ case 'Ed25519':
73
+ candidate = jwk.crv === 'Ed25519';
74
+ break;
75
+ case 'EdDSA':
76
+ candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
77
+ break;
75
78
  }
76
79
  }
77
80
  return candidate;
@@ -10,7 +10,7 @@ function isCloudflareWorkers() {
10
10
  let USER_AGENT;
11
11
  if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
12
12
  const NAME = 'jose';
13
- const VERSION = 'v5.9.6';
13
+ const VERSION = 'v5.10.0';
14
14
  USER_AGENT = `${NAME}/${VERSION}`;
15
15
  }
16
16
  export const jwksCache = Symbol();
@@ -33,7 +33,7 @@ export async function importJWK(jwk, alg) {
33
33
  }
34
34
  return decodeBase64URL(jwk.k);
35
35
  case 'RSA':
36
- if (jwk.oth !== undefined) {
36
+ if ('oth' in jwk && jwk.oth !== undefined) {
37
37
  throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
38
38
  }
39
39
  case 'EC':
@@ -76,6 +76,11 @@ export function checkSigCryptoKey(key, alg, ...usages) {
76
76
  }
77
77
  break;
78
78
  }
79
+ case 'Ed25519': {
80
+ if (!isAlgorithm(key.algorithm, 'Ed25519'))
81
+ throw unusable('Ed25519');
82
+ break;
83
+ }
79
84
  case 'ES256':
80
85
  case 'ES384':
81
86
  case 'ES512': {
@@ -14,6 +14,7 @@ export default function dsaDigest(alg) {
14
14
  case 'RS512':
15
15
  case 'ES512':
16
16
  return 'sha512';
17
+ case 'Ed25519':
17
18
  case 'EdDSA':
18
19
  return undefined;
19
20
  default:
@@ -61,6 +61,8 @@ export async function generateKeyPair(alg, options) {
61
61
  return generate('ec', { namedCurve: 'P-384' });
62
62
  case 'ES512':
63
63
  return generate('ec', { namedCurve: 'P-521' });
64
+ case 'Ed25519':
65
+ return generate('ed25519');
64
66
  case 'EdDSA': {
65
67
  switch (options?.crv) {
66
68
  case undefined:
@@ -42,6 +42,11 @@ export default function keyForCrypto(alg, key) {
42
42
  }
43
43
  let options;
44
44
  switch (alg) {
45
+ case 'Ed25519':
46
+ if (asymmetricKeyType !== 'ed25519') {
47
+ throw new TypeError(`Invalid key for this operation, its asymmetricKeyType must be ed25519`);
48
+ }
49
+ break;
45
50
  case 'EdDSA':
46
51
  if (!['ed25519', 'ed448'].includes(asymmetricKeyType)) {
47
52
  throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ed25519 or ed448');
@@ -96,16 +96,6 @@ export interface JWK_RSA_Private extends JWK_RSA_Public, JWKParameters {
96
96
  dp: string
97
97
  /** RSA JWK "dq" (Second Factor CRT Exponent) Parameter */
98
98
  dq: string
99
- /**
100
- * RSA JWK "oth" (Other Primes Info) Parameter
101
- *
102
- * This parameter is not supported
103
- */
104
- oth?: Array<{
105
- d?: string
106
- r?: string
107
- t?: string
108
- }>
109
99
  /** RSA JWK "p" (First Prime Factor) Parameter */
110
100
  p: string
111
101
  /** RSA JWK "q" (Second Prime Factor) Parameter */
@@ -154,16 +144,6 @@ export interface JWK extends JWKParameters {
154
144
  k?: string
155
145
  /** RSA JWK "n" (Modulus) Parameter */
156
146
  n?: string
157
- /**
158
- * Private RSA JWK "oth" (Other Primes Info) Parameter
159
- *
160
- * This parameter is not supported
161
- */
162
- oth?: Array<{
163
- d?: string
164
- r?: string
165
- t?: string
166
- }>
167
147
  /** Private RSA JWK "p" (First Prime Factor) Parameter */
168
148
  p?: string
169
149
  /** Private RSA JWK "q" (Second Prime Factor) Parameter */
@@ -499,10 +479,13 @@ export interface JWTClaimVerificationOptions {
499
479
  audience?: string | string[]
500
480
 
501
481
  /**
502
- * Expected clock tolerance
482
+ * Clock skew tolerance
503
483
  *
504
484
  * - In seconds when number (e.g. 5)
505
- * - Parsed as seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours").
485
+ * - Resolved into a number of seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours").
486
+ *
487
+ * Used when validating the JWT "nbf" (Not Before) and "exp" (Expiration Time) claims, and when
488
+ * validating the "iat" (Issued At) claim if the {@link maxTokenAge `maxTokenAge` option} is set.
506
489
  */
507
490
  clockTolerance?: string | number
508
491
 
@@ -517,7 +500,7 @@ export interface JWTClaimVerificationOptions {
517
500
  * Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value.
518
501
  *
519
502
  * - In seconds when number (e.g. 5)
520
- * - Parsed as seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours").
503
+ * - Resolved into a number of seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours").
521
504
  *
522
505
  * This option makes the JWT "iat" (Issued At) Claim presence required.
523
506
  */
@@ -542,13 +525,11 @@ export interface JWTClaimVerificationOptions {
542
525
 
543
526
  /**
544
527
  * Array of required Claim Names that must be present in the JWT Claims Set. Default is that: if
545
- * the {@link JWTClaimVerificationOptions.issuer `issuer` option} is set, then JWT "iss" (Issuer)
546
- * Claim must be present; if the {@link JWTClaimVerificationOptions.audience `audience` option} is
547
- * set, then JWT "aud" (Audience) Claim must be present; if the
548
- * {@link JWTClaimVerificationOptions.subject `subject` option} is set, then JWT "sub" (Subject)
549
- * Claim must be present; if the
550
- * {@link JWTClaimVerificationOptions.maxTokenAge `maxTokenAge` option} is set, then JWT "iat"
551
- * (Issued At) Claim must be present.
528
+ * the {@link issuer `issuer` option} is set, then JWT "iss" (Issuer) Claim must be present; if the
529
+ * {@link audience `audience` option} is set, then JWT "aud" (Audience) Claim must be present; if
530
+ * the {@link subject `subject` option} is set, then JWT "sub" (Subject) Claim must be present; if
531
+ * the {@link maxTokenAge `maxTokenAge` option} is set, then JWT "iat" (Issued At) Claim must be
532
+ * present.
552
533
  */
553
534
  requiredClaims?: string[]
554
535
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jose",
3
- "version": "5.9.6",
3
+ "version": "5.10.0",
4
4
  "description": "JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes",
5
5
  "keywords": [
6
6
  "browser",