jose 4.4.0 → 4.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/README.md CHANGED
@@ -42,10 +42,10 @@ import * as jose from 'https://deno.land/x/jose/index.ts'
42
42
 
43
43
  - JSON Web Tokens (JWT)
44
44
  - [Signing](docs/classes/jwt_sign.SignJWT.md#readme)
45
- - [Verification & Claims Set Validation](docs/functions/jwt_verify.jwtVerify.md#readme)
45
+ - [Verification & JWT Claims Set Validation](docs/functions/jwt_verify.jwtVerify.md#readme)
46
46
  - Encrypted JSON Web Tokens
47
47
  - [Encryption](docs/classes/jwt_encrypt.EncryptJWT.md#readme)
48
- - [Decryption & Claims Set Validation](docs/functions/jwt_decrypt.jwtDecrypt.md#readme)
48
+ - [Decryption & JWT Claims Set Validation](docs/functions/jwt_decrypt.jwtDecrypt.md#readme)
49
49
  - Key Import
50
50
  - [JWK Import](docs/functions/key_import.importJWK.md#readme)
51
51
  - [Public Key Import (SPKI)](docs/functions/key_import.importSPKI.md#readme)
@@ -72,6 +72,7 @@ import * as jose from 'https://deno.land/x/jose/index.ts'
72
72
  - [Public Key Export](docs/functions/key_export.exportSPKI.md#readme)
73
73
  - Utilities
74
74
  - [Decoding Token's Protected Header](docs/functions/util_decode_protected_header.decodeProtectedHeader.md#readme)
75
+ - [Decoding JWT Claims Set](docs/functions/util_decode_jwt.decodeJwt.md#readme)
75
76
  - [Unsecured JWT](docs/classes/jwt_unsecured.UnsecuredJWT.md#readme)
76
77
  - [JOSE Errors](docs/modules/util_errors.md#readme)
77
78
 
@@ -90,7 +91,7 @@ import * as jose from 'https://deno.land/x/jose/index.ts'
90
91
 
91
92
  | Version | Security Fixes 🔑 | Other Bug Fixes 🐞 | New Features ⭐ |
92
93
  | ------- | --------- | -------- | -------- |
93
- | [4.x.x](https://github.com/panva/jose) | ✅ | ✅ | ✅ |
94
+ | [4.x.x](https://github.com/panva/jose/tree/v4.x) | ✅ | ✅ | ✅ |
94
95
  | [3.x.x](https://github.com/panva/jose/tree/v3.x) | ✅ | ✅ until 2022-04-30 | ❌ |
95
96
  | [2.x.x](https://github.com/panva/jose/tree/v2.x) | ✅ | ✅ until 2022-04-30 | ❌ |
96
97
  | [1.x.x](https://github.com/panva/jose/tree/v1.x) | ✅ | ❌ | ❌ |
@@ -22,6 +22,7 @@ export { UnsecuredJWT } from './jwt/unsecured.js';
22
22
  export { exportPKCS8, exportSPKI, exportJWK } from './key/export.js';
23
23
  export { importSPKI, importPKCS8, importX509, importJWK } from './key/import.js';
24
24
  export { decodeProtectedHeader } from './util/decode_protected_header.js';
25
+ export { decodeJwt } from './util/decode_jwt.js';
25
26
  import * as errors_1 from './util/errors.js';
26
27
  export { errors_1 as errors };
27
28
  export { generateKeyPair } from './key/generate_key_pair.js';
@@ -38,17 +38,14 @@ export class LocalJWKSet {
38
38
  this._jwks = clone(jwks);
39
39
  }
40
40
  async getKey(protectedHeader, token) {
41
- const joseHeader = {
42
- ...protectedHeader,
43
- ...token.header,
44
- };
41
+ const { alg, kid } = { ...protectedHeader, ...token.header };
45
42
  const candidates = this._jwks.keys.filter((jwk) => {
46
- let candidate = jwk.kty === getKtyFromAlg(joseHeader.alg);
47
- if (candidate && typeof joseHeader.kid === 'string') {
48
- candidate = joseHeader.kid === jwk.kid;
43
+ let candidate = jwk.kty === getKtyFromAlg(alg);
44
+ if (candidate && typeof kid === 'string') {
45
+ candidate = kid === jwk.kid;
49
46
  }
50
47
  if (candidate && typeof jwk.alg === 'string') {
51
- candidate = joseHeader.alg === jwk.alg;
48
+ candidate = alg === jwk.alg;
52
49
  }
53
50
  if (candidate && typeof jwk.use === 'string') {
54
51
  candidate = jwk.use === 'sig';
@@ -56,11 +53,11 @@ export class LocalJWKSet {
56
53
  if (candidate && Array.isArray(jwk.key_ops)) {
57
54
  candidate = jwk.key_ops.includes('verify');
58
55
  }
59
- if (candidate && joseHeader.alg === 'EdDSA') {
56
+ if (candidate && alg === 'EdDSA') {
60
57
  candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
61
58
  }
62
59
  if (candidate) {
63
- switch (joseHeader.alg) {
60
+ switch (alg) {
64
61
  case 'ES256':
65
62
  candidate = jwk.crv === 'P-256';
66
63
  break;
@@ -73,7 +70,6 @@ export class LocalJWKSet {
73
70
  case 'ES512':
74
71
  candidate = jwk.crv === 'P-521';
75
72
  break;
76
- default:
77
73
  }
78
74
  }
79
75
  return candidate;
@@ -86,14 +82,14 @@ export class LocalJWKSet {
86
82
  throw new JWKSMultipleMatchingKeys();
87
83
  }
88
84
  const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
89
- if (cached[joseHeader.alg] === undefined) {
90
- const keyObject = await importJWK({ ...jwk, ext: true }, joseHeader.alg);
85
+ if (cached[alg] === undefined) {
86
+ const keyObject = await importJWK({ ...jwk, ext: true }, alg);
91
87
  if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
92
88
  throw new JWKSInvalid('JSON Web Key Set members must be public keys');
93
89
  }
94
- cached[joseHeader.alg] = keyObject;
90
+ cached[alg] = keyObject;
95
91
  }
96
- return cached[joseHeader.alg];
92
+ return cached[alg];
97
93
  }
98
94
  }
99
95
  export function createLocalJWKSet(jwks) {
@@ -1,4 +1,5 @@
1
1
  import fetchJwks from '../runtime/fetch_jwks.js';
2
+ import { isCloudflareWorkers } from '../runtime/env.js';
2
3
  import { JWKSInvalid, JWKSNoMatchingKey } from '../util/errors.js';
3
4
  import { isJWKSLike, LocalJWKSet } from './local.js';
4
5
  class RemoteJWKSet extends LocalJWKSet {
@@ -39,6 +40,19 @@ class RemoteJWKSet extends LocalJWKSet {
39
40
  }
40
41
  }
41
42
  async reload() {
43
+ if (this._pendingFetch && isCloudflareWorkers()) {
44
+ return new Promise((resolve) => {
45
+ const isDone = () => {
46
+ if (this._pendingFetch === undefined) {
47
+ resolve();
48
+ }
49
+ else {
50
+ setTimeout(isDone, 5);
51
+ }
52
+ };
53
+ isDone();
54
+ });
55
+ }
42
56
  if (!this._pendingFetch) {
43
57
  this._pendingFetch = fetchJwks(this._url, this._timeoutDuration, this._options)
44
58
  .then((json) => {
@@ -0,0 +1,32 @@
1
+ import { decode as base64url } from './base64url.js';
2
+ import { decoder } from '../lib/buffer_utils.js';
3
+ import isObject from '../lib/is_object.js';
4
+ import { JWTInvalid } from './errors.js';
5
+ export function decodeJwt(jwt) {
6
+ if (typeof jwt !== 'string')
7
+ throw new JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');
8
+ const { 1: payload, length } = jwt.split('.');
9
+ if (length === 5)
10
+ throw new JWTInvalid('Only JWTs using Compact JWS serialization can be decoded');
11
+ if (length !== 3)
12
+ throw new JWTInvalid('Invalid JWT');
13
+ if (!payload)
14
+ throw new JWTInvalid('JWTs must contain a payload');
15
+ let decoded;
16
+ try {
17
+ decoded = base64url(payload);
18
+ }
19
+ catch (_a) {
20
+ throw new JWTInvalid('Failed to parse the base64url encoded payload');
21
+ }
22
+ let result;
23
+ try {
24
+ result = JSON.parse(decoder.decode(decoded));
25
+ }
26
+ catch (_b) {
27
+ throw new JWTInvalid('Failed to parse the decoded payload as JSON');
28
+ }
29
+ if (!isObject(result))
30
+ throw new JWTInvalid('Invalid JWT Claims Set');
31
+ return result;
32
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.base64url = exports.generateSecret = exports.generateKeyPair = exports.errors = exports.decodeProtectedHeader = exports.importJWK = exports.importX509 = exports.importPKCS8 = exports.importSPKI = exports.exportJWK = exports.exportSPKI = exports.exportPKCS8 = exports.UnsecuredJWT = exports.createRemoteJWKSet = exports.createLocalJWKSet = exports.EmbeddedJWK = exports.calculateJwkThumbprint = exports.EncryptJWT = exports.SignJWT = exports.GeneralSign = exports.FlattenedSign = exports.CompactSign = exports.FlattenedEncrypt = exports.CompactEncrypt = exports.jwtDecrypt = exports.jwtVerify = exports.generalVerify = exports.flattenedVerify = exports.compactVerify = exports.GeneralEncrypt = exports.generalDecrypt = exports.flattenedDecrypt = exports.compactDecrypt = void 0;
3
+ exports.base64url = exports.generateSecret = exports.generateKeyPair = exports.errors = exports.decodeJwt = exports.decodeProtectedHeader = exports.importJWK = exports.importX509 = exports.importPKCS8 = exports.importSPKI = exports.exportJWK = exports.exportSPKI = exports.exportPKCS8 = exports.UnsecuredJWT = exports.createRemoteJWKSet = exports.createLocalJWKSet = exports.EmbeddedJWK = exports.calculateJwkThumbprint = exports.EncryptJWT = exports.SignJWT = exports.GeneralSign = exports.FlattenedSign = exports.CompactSign = exports.FlattenedEncrypt = exports.CompactEncrypt = exports.jwtDecrypt = exports.jwtVerify = exports.generalVerify = exports.flattenedVerify = exports.compactVerify = exports.GeneralEncrypt = exports.generalDecrypt = exports.flattenedDecrypt = exports.compactDecrypt = void 0;
4
4
  var decrypt_js_1 = require("./jwe/compact/decrypt.js");
5
5
  Object.defineProperty(exports, "compactDecrypt", { enumerable: true, get: function () { return decrypt_js_1.compactDecrypt; } });
6
6
  var decrypt_js_2 = require("./jwe/flattened/decrypt.js");
@@ -54,6 +54,8 @@ Object.defineProperty(exports, "importX509", { enumerable: true, get: function (
54
54
  Object.defineProperty(exports, "importJWK", { enumerable: true, get: function () { return import_js_1.importJWK; } });
55
55
  var decode_protected_header_js_1 = require("./util/decode_protected_header.js");
56
56
  Object.defineProperty(exports, "decodeProtectedHeader", { enumerable: true, get: function () { return decode_protected_header_js_1.decodeProtectedHeader; } });
57
+ var decode_jwt_js_1 = require("./util/decode_jwt.js");
58
+ Object.defineProperty(exports, "decodeJwt", { enumerable: true, get: function () { return decode_jwt_js_1.decodeJwt; } });
57
59
  exports.errors = require("./util/errors.js");
58
60
  var generate_key_pair_js_1 = require("./key/generate_key_pair.js");
59
61
  Object.defineProperty(exports, "generateKeyPair", { enumerable: true, get: function () { return generate_key_pair_js_1.generateKeyPair; } });
@@ -42,17 +42,14 @@ class LocalJWKSet {
42
42
  this._jwks = clone(jwks);
43
43
  }
44
44
  async getKey(protectedHeader, token) {
45
- const joseHeader = {
46
- ...protectedHeader,
47
- ...token.header,
48
- };
45
+ const { alg, kid } = { ...protectedHeader, ...token.header };
49
46
  const candidates = this._jwks.keys.filter((jwk) => {
50
- let candidate = jwk.kty === getKtyFromAlg(joseHeader.alg);
51
- if (candidate && typeof joseHeader.kid === 'string') {
52
- candidate = joseHeader.kid === jwk.kid;
47
+ let candidate = jwk.kty === getKtyFromAlg(alg);
48
+ if (candidate && typeof kid === 'string') {
49
+ candidate = kid === jwk.kid;
53
50
  }
54
51
  if (candidate && typeof jwk.alg === 'string') {
55
- candidate = joseHeader.alg === jwk.alg;
52
+ candidate = alg === jwk.alg;
56
53
  }
57
54
  if (candidate && typeof jwk.use === 'string') {
58
55
  candidate = jwk.use === 'sig';
@@ -60,11 +57,11 @@ class LocalJWKSet {
60
57
  if (candidate && Array.isArray(jwk.key_ops)) {
61
58
  candidate = jwk.key_ops.includes('verify');
62
59
  }
63
- if (candidate && joseHeader.alg === 'EdDSA') {
60
+ if (candidate && alg === 'EdDSA') {
64
61
  candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
65
62
  }
66
63
  if (candidate) {
67
- switch (joseHeader.alg) {
64
+ switch (alg) {
68
65
  case 'ES256':
69
66
  candidate = jwk.crv === 'P-256';
70
67
  break;
@@ -77,7 +74,6 @@ class LocalJWKSet {
77
74
  case 'ES512':
78
75
  candidate = jwk.crv === 'P-521';
79
76
  break;
80
- default:
81
77
  }
82
78
  }
83
79
  return candidate;
@@ -90,14 +86,14 @@ class LocalJWKSet {
90
86
  throw new errors_js_1.JWKSMultipleMatchingKeys();
91
87
  }
92
88
  const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
93
- if (cached[joseHeader.alg] === undefined) {
94
- const keyObject = await (0, import_js_1.importJWK)({ ...jwk, ext: true }, joseHeader.alg);
89
+ if (cached[alg] === undefined) {
90
+ const keyObject = await (0, import_js_1.importJWK)({ ...jwk, ext: true }, alg);
95
91
  if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
96
92
  throw new errors_js_1.JWKSInvalid('JSON Web Key Set members must be public keys');
97
93
  }
98
- cached[joseHeader.alg] = keyObject;
94
+ cached[alg] = keyObject;
99
95
  }
100
- return cached[joseHeader.alg];
96
+ return cached[alg];
101
97
  }
102
98
  }
103
99
  exports.LocalJWKSet = LocalJWKSet;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createRemoteJWKSet = void 0;
4
4
  const fetch_jwks_js_1 = require("../runtime/fetch_jwks.js");
5
+ const env_js_1 = require("../runtime/env.js");
5
6
  const errors_js_1 = require("../util/errors.js");
6
7
  const local_js_1 = require("./local.js");
7
8
  class RemoteJWKSet extends local_js_1.LocalJWKSet {
@@ -42,6 +43,19 @@ class RemoteJWKSet extends local_js_1.LocalJWKSet {
42
43
  }
43
44
  }
44
45
  async reload() {
46
+ if (this._pendingFetch && (0, env_js_1.isCloudflareWorkers)()) {
47
+ return new Promise((resolve) => {
48
+ const isDone = () => {
49
+ if (this._pendingFetch === undefined) {
50
+ resolve();
51
+ }
52
+ else {
53
+ setTimeout(isDone, 5);
54
+ }
55
+ };
56
+ isDone();
57
+ });
58
+ }
45
59
  if (!this._pendingFetch) {
46
60
  this._pendingFetch = (0, fetch_jwks_js_1.default)(this._url, this._timeoutDuration, this._options)
47
61
  .then((json) => {
@@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.decode = exports.encode = exports.encodeBase64 = exports.decodeBase64 = void 0;
4
4
  const buffer_1 = require("buffer");
5
5
  const buffer_utils_js_1 = require("../lib/buffer_utils.js");
6
- let encodeImpl;
6
+ let encode;
7
+ exports.encode = encode;
7
8
  function normalize(input) {
8
9
  let encoded = input;
9
10
  if (encoded instanceof Uint8Array) {
@@ -12,15 +13,14 @@ function normalize(input) {
12
13
  return encoded;
13
14
  }
14
15
  if (buffer_1.Buffer.isEncoding('base64url')) {
15
- encodeImpl = (input) => buffer_1.Buffer.from(input).toString('base64url');
16
+ exports.encode = encode = (input) => buffer_1.Buffer.from(input).toString('base64url');
16
17
  }
17
18
  else {
18
- encodeImpl = (input) => buffer_1.Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
19
+ exports.encode = encode = (input) => buffer_1.Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
19
20
  }
20
21
  const decodeBase64 = (input) => buffer_1.Buffer.from(input, 'base64');
21
22
  exports.decodeBase64 = decodeBase64;
22
23
  const encodeBase64 = (input) => buffer_1.Buffer.from(input).toString('base64');
23
24
  exports.encodeBase64 = encodeBase64;
24
- exports.encode = encodeImpl;
25
25
  const decode = (input) => buffer_1.Buffer.from(normalize(input), 'base64');
26
26
  exports.decode = decode;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decodeJwt = void 0;
4
+ const base64url_js_1 = require("./base64url.js");
5
+ const buffer_utils_js_1 = require("../lib/buffer_utils.js");
6
+ const is_object_js_1 = require("../lib/is_object.js");
7
+ const errors_js_1 = require("./errors.js");
8
+ function decodeJwt(jwt) {
9
+ if (typeof jwt !== 'string')
10
+ throw new errors_js_1.JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');
11
+ const { 1: payload, length } = jwt.split('.');
12
+ if (length === 5)
13
+ throw new errors_js_1.JWTInvalid('Only JWTs using Compact JWS serialization can be decoded');
14
+ if (length !== 3)
15
+ throw new errors_js_1.JWTInvalid('Invalid JWT');
16
+ if (!payload)
17
+ throw new errors_js_1.JWTInvalid('JWTs must contain a payload');
18
+ let decoded;
19
+ try {
20
+ decoded = (0, base64url_js_1.decode)(payload);
21
+ }
22
+ catch {
23
+ throw new errors_js_1.JWTInvalid('Failed to parse the base64url encoded payload');
24
+ }
25
+ let result;
26
+ try {
27
+ result = JSON.parse(buffer_utils_js_1.decoder.decode(decoded));
28
+ }
29
+ catch {
30
+ throw new errors_js_1.JWTInvalid('Failed to parse the decoded payload as JSON');
31
+ }
32
+ if (!(0, is_object_js_1.default)(result))
33
+ throw new errors_js_1.JWTInvalid('Invalid JWT Claims Set');
34
+ return result;
35
+ }
36
+ exports.decodeJwt = decodeJwt;
@@ -22,6 +22,7 @@ export { UnsecuredJWT } from './jwt/unsecured.js';
22
22
  export { exportPKCS8, exportSPKI, exportJWK } from './key/export.js';
23
23
  export { importSPKI, importPKCS8, importX509, importJWK } from './key/import.js';
24
24
  export { decodeProtectedHeader } from './util/decode_protected_header.js';
25
+ export { decodeJwt } from './util/decode_jwt.js';
25
26
  export * as errors from './util/errors.js';
26
27
  export { generateKeyPair } from './key/generate_key_pair.js';
27
28
  export { generateSecret } from './key/generate_secret.js';
@@ -38,17 +38,14 @@ export class LocalJWKSet {
38
38
  this._jwks = clone(jwks);
39
39
  }
40
40
  async getKey(protectedHeader, token) {
41
- const joseHeader = {
42
- ...protectedHeader,
43
- ...token.header,
44
- };
41
+ const { alg, kid } = { ...protectedHeader, ...token.header };
45
42
  const candidates = this._jwks.keys.filter((jwk) => {
46
- let candidate = jwk.kty === getKtyFromAlg(joseHeader.alg);
47
- if (candidate && typeof joseHeader.kid === 'string') {
48
- candidate = joseHeader.kid === jwk.kid;
43
+ let candidate = jwk.kty === getKtyFromAlg(alg);
44
+ if (candidate && typeof kid === 'string') {
45
+ candidate = kid === jwk.kid;
49
46
  }
50
47
  if (candidate && typeof jwk.alg === 'string') {
51
- candidate = joseHeader.alg === jwk.alg;
48
+ candidate = alg === jwk.alg;
52
49
  }
53
50
  if (candidate && typeof jwk.use === 'string') {
54
51
  candidate = jwk.use === 'sig';
@@ -56,11 +53,11 @@ export class LocalJWKSet {
56
53
  if (candidate && Array.isArray(jwk.key_ops)) {
57
54
  candidate = jwk.key_ops.includes('verify');
58
55
  }
59
- if (candidate && joseHeader.alg === 'EdDSA') {
56
+ if (candidate && alg === 'EdDSA') {
60
57
  candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
61
58
  }
62
59
  if (candidate) {
63
- switch (joseHeader.alg) {
60
+ switch (alg) {
64
61
  case 'ES256':
65
62
  candidate = jwk.crv === 'P-256';
66
63
  break;
@@ -73,7 +70,6 @@ export class LocalJWKSet {
73
70
  case 'ES512':
74
71
  candidate = jwk.crv === 'P-521';
75
72
  break;
76
- default:
77
73
  }
78
74
  }
79
75
  return candidate;
@@ -86,14 +82,14 @@ export class LocalJWKSet {
86
82
  throw new JWKSMultipleMatchingKeys();
87
83
  }
88
84
  const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
89
- if (cached[joseHeader.alg] === undefined) {
90
- const keyObject = await importJWK({ ...jwk, ext: true }, joseHeader.alg);
85
+ if (cached[alg] === undefined) {
86
+ const keyObject = await importJWK({ ...jwk, ext: true }, alg);
91
87
  if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
92
88
  throw new JWKSInvalid('JSON Web Key Set members must be public keys');
93
89
  }
94
- cached[joseHeader.alg] = keyObject;
90
+ cached[alg] = keyObject;
95
91
  }
96
- return cached[joseHeader.alg];
92
+ return cached[alg];
97
93
  }
98
94
  }
99
95
  export function createLocalJWKSet(jwks) {
@@ -1,4 +1,5 @@
1
1
  import fetchJwks from '../runtime/fetch_jwks.js';
2
+ import { isCloudflareWorkers } from '../runtime/env.js';
2
3
  import { JWKSInvalid, JWKSNoMatchingKey } from '../util/errors.js';
3
4
  import { isJWKSLike, LocalJWKSet } from './local.js';
4
5
  class RemoteJWKSet extends LocalJWKSet {
@@ -39,6 +40,19 @@ class RemoteJWKSet extends LocalJWKSet {
39
40
  }
40
41
  }
41
42
  async reload() {
43
+ if (this._pendingFetch && isCloudflareWorkers()) {
44
+ return new Promise((resolve) => {
45
+ const isDone = () => {
46
+ if (this._pendingFetch === undefined) {
47
+ resolve();
48
+ }
49
+ else {
50
+ setTimeout(isDone, 5);
51
+ }
52
+ };
53
+ isDone();
54
+ });
55
+ }
42
56
  if (!this._pendingFetch) {
43
57
  this._pendingFetch = fetchJwks(this._url, this._timeoutDuration, this._options)
44
58
  .then((json) => {
@@ -1,6 +1,6 @@
1
1
  import { Buffer } from 'buffer';
2
2
  import { decoder } from '../lib/buffer_utils.js';
3
- let encodeImpl;
3
+ let encode;
4
4
  function normalize(input) {
5
5
  let encoded = input;
6
6
  if (encoded instanceof Uint8Array) {
@@ -9,12 +9,12 @@ function normalize(input) {
9
9
  return encoded;
10
10
  }
11
11
  if (Buffer.isEncoding('base64url')) {
12
- encodeImpl = (input) => Buffer.from(input).toString('base64url');
12
+ encode = (input) => Buffer.from(input).toString('base64url');
13
13
  }
14
14
  else {
15
- encodeImpl = (input) => Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
15
+ encode = (input) => Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
16
16
  }
17
17
  export const decodeBase64 = (input) => Buffer.from(input, 'base64');
18
18
  export const encodeBase64 = (input) => Buffer.from(input).toString('base64');
19
- export const encode = encodeImpl;
19
+ export { encode };
20
20
  export const decode = (input) => Buffer.from(normalize(input), 'base64');
@@ -0,0 +1,32 @@
1
+ import { decode as base64url } from './base64url.js';
2
+ import { decoder } from '../lib/buffer_utils.js';
3
+ import isObject from '../lib/is_object.js';
4
+ import { JWTInvalid } from './errors.js';
5
+ export function decodeJwt(jwt) {
6
+ if (typeof jwt !== 'string')
7
+ throw new JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');
8
+ const { 1: payload, length } = jwt.split('.');
9
+ if (length === 5)
10
+ throw new JWTInvalid('Only JWTs using Compact JWS serialization can be decoded');
11
+ if (length !== 3)
12
+ throw new JWTInvalid('Invalid JWT');
13
+ if (!payload)
14
+ throw new JWTInvalid('JWTs must contain a payload');
15
+ let decoded;
16
+ try {
17
+ decoded = base64url(payload);
18
+ }
19
+ catch {
20
+ throw new JWTInvalid('Failed to parse the base64url encoded payload');
21
+ }
22
+ let result;
23
+ try {
24
+ result = JSON.parse(decoder.decode(decoded));
25
+ }
26
+ catch {
27
+ throw new JWTInvalid('Failed to parse the decoded payload as JSON');
28
+ }
29
+ if (!isObject(result))
30
+ throw new JWTInvalid('Invalid JWT Claims Set');
31
+ return result;
32
+ }
@@ -36,6 +36,7 @@ export { exportPKCS8, exportSPKI, exportJWK } from './key/export';
36
36
  export { importSPKI, importPKCS8, importX509, importJWK } from './key/import';
37
37
  export type { PEMImportOptions } from './key/import';
38
38
  export { decodeProtectedHeader } from './util/decode_protected_header';
39
+ export { decodeJwt } from './util/decode_jwt';
39
40
  export type { ProtectedHeaderParameters } from './util/decode_protected_header';
40
41
  export * as errors from './util/errors';
41
42
  export { generateKeyPair } from './key/generate_key_pair';
@@ -0,0 +1,2 @@
1
+ import type { JWTPayload } from '../types';
2
+ export declare function decodeJwt(jwt: string): JWTPayload;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jose",
3
- "version": "4.4.0",
3
+ "version": "4.5.0",
4
4
  "description": "'JSON Web Almost Everything' - JWA, JWS, JWE, JWT, JWK, JWKS with no dependencies using runtime's native crypto",
5
5
  "keywords": [
6
6
  "browser",