@astronautlabs/jwt 0.0.12

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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +107 -0
  3. package/demo.key +27 -0
  4. package/demo8.key +28 -0
  5. package/dist/browser/base64url.d.ts +4 -0
  6. package/dist/browser/base64url.js +18 -0
  7. package/dist/browser/base64url.js.map +1 -0
  8. package/dist/browser/index.d.ts +5 -0
  9. package/dist/browser/index.js +21 -0
  10. package/dist/browser/index.js.map +1 -0
  11. package/dist/browser/utils.d.ts +6 -0
  12. package/dist/browser/utils.js +24 -0
  13. package/dist/browser/utils.js.map +1 -0
  14. package/dist/browser/webcrypto-jwt.d.ts +22 -0
  15. package/dist/browser/webcrypto-jwt.js +378 -0
  16. package/dist/browser/webcrypto-jwt.js.map +1 -0
  17. package/dist/browser/webcrypto-jwt.test.d.ts +1 -0
  18. package/dist/browser/webcrypto-jwt.test.js +6 -0
  19. package/dist/browser/webcrypto-jwt.test.js.map +1 -0
  20. package/dist/common/expiry.d.ts +1 -0
  21. package/dist/common/expiry.js +25 -0
  22. package/dist/common/expiry.js.map +1 -0
  23. package/dist/common/index.d.ts +2 -0
  24. package/dist/common/index.js +15 -0
  25. package/dist/common/index.js.map +1 -0
  26. package/dist/common/interface.d.ts +38 -0
  27. package/dist/common/interface.js +3 -0
  28. package/dist/common/interface.js.map +1 -0
  29. package/dist/engine.test.d.ts +10 -0
  30. package/dist/engine.test.js +295 -0
  31. package/dist/engine.test.js.map +1 -0
  32. package/dist/fixtures/es256.fixture.d.ts +6 -0
  33. package/dist/fixtures/es256.fixture.js +10 -0
  34. package/dist/fixtures/es256.fixture.js.map +1 -0
  35. package/dist/fixtures/hs256.fixture.d.ts +6 -0
  36. package/dist/fixtures/hs256.fixture.js +10 -0
  37. package/dist/fixtures/hs256.fixture.js.map +1 -0
  38. package/dist/fixtures/hs384.fixture.d.ts +6 -0
  39. package/dist/fixtures/hs384.fixture.js +10 -0
  40. package/dist/fixtures/hs384.fixture.js.map +1 -0
  41. package/dist/fixtures/hs512.fixture.d.ts +6 -0
  42. package/dist/fixtures/hs512.fixture.js +10 -0
  43. package/dist/fixtures/hs512.fixture.js.map +1 -0
  44. package/dist/fixtures/rs256.fixture.d.ts +6 -0
  45. package/dist/fixtures/rs256.fixture.js +10 -0
  46. package/dist/fixtures/rs256.fixture.js.map +1 -0
  47. package/dist/fixtures/rs512.fixture.d.ts +6 -0
  48. package/dist/fixtures/rs512.fixture.js +10 -0
  49. package/dist/fixtures/rs512.fixture.js.map +1 -0
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.js +18 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/node/engine.test.d.ts +1 -0
  54. package/dist/node/engine.test.js +6 -0
  55. package/dist/node/engine.test.js.map +1 -0
  56. package/dist/node/index.d.ts +9 -0
  57. package/dist/node/index.js +117 -0
  58. package/dist/node/index.js.map +1 -0
  59. package/dist/test.d.ts +1 -0
  60. package/dist/test.js +9 -0
  61. package/dist/test.js.map +1 -0
  62. package/karma.conf.ts +59 -0
  63. package/package.json +46 -0
  64. package/src/browser/base64url.ts +12 -0
  65. package/src/browser/index.ts +6 -0
  66. package/src/browser/utils.ts +20 -0
  67. package/src/browser/webcrypto-jwt.test.ts +4 -0
  68. package/src/browser/webcrypto-jwt.ts +351 -0
  69. package/src/common/expiry.ts +25 -0
  70. package/src/common/index.ts +2 -0
  71. package/src/common/interface.ts +47 -0
  72. package/src/engine.test.ts +173 -0
  73. package/src/fixtures/es256.fixture.ts +25 -0
  74. package/src/fixtures/hs256.fixture.ts +6 -0
  75. package/src/fixtures/hs384.fixture.ts +6 -0
  76. package/src/fixtures/hs512.fixture.ts +6 -0
  77. package/src/fixtures/rs256.fixture.ts +81 -0
  78. package/src/fixtures/rs512.fixture.ts +81 -0
  79. package/src/index.ts +5 -0
  80. package/src/node/engine.test.ts +4 -0
  81. package/src/node/index.ts +56 -0
  82. package/src/test.ts +7 -0
  83. package/tsconfig.json +37 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Astronaut Labs, LLC.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # @/jwt
2
+
3
+ > This library is **Alpha quality** in the `0.0.x` series (no automatic updates
4
+ > by semver). Please take caution if you choose to use it, and do not use it
5
+ > in production. We welcome PRs for fixes, features and general improvements.
6
+
7
+ A simple isomorphic JWT library (works in browser and Node.js) with support for
8
+ signing and verifying JWTs using a number of common algorithms.
9
+
10
+ # Installation
11
+
12
+ ```bash
13
+ npm install @astronautlabs/jwt
14
+ ```
15
+
16
+ # Usage
17
+
18
+ ## Common Options
19
+
20
+ - `now` -- Specify the UNIX wall clock time to use when enforcing `exp` claims. When not specified, `Date.now()` is used.
21
+ - `algorithm` -- The signature algorithm to use. See [Supported Algorithms](#supported-algorithms) for the options.
22
+ - `secretOrKey` -- The key to use for the operation. When using asymmetric
23
+ algorithms (like `RS256`, `ES256`, etc) you should pass public keys for
24
+ `validate()` and private keys for `encode()`
25
+
26
+ ## Signing
27
+
28
+ ```typescript
29
+ async encode(claims: any, options: EncodeOptions): Promise<Token>
30
+ ```
31
+
32
+ ### Remarks
33
+
34
+ Returns a `Token` object with the given claims, and signed by the credentials
35
+ specified in `options` (see `algorithm` and `secretOrKey`).
36
+
37
+ ### Example
38
+
39
+ ```typescript
40
+ import { JWT } from '@astronautlabs/jwt';
41
+
42
+ try {
43
+ let token = await JWT.encode({ sub: 123 }, { algorithm: 'HS256', secretOrKey: 'stuff' });
44
+ console.dir(token); // => { string: 'eY...', claims: { sub: ..., ... } }
45
+ } catch (e) {
46
+ console.error('Failed to validate token: ');
47
+ console.error(e);
48
+ }
49
+ ```
50
+
51
+
52
+ ## Validation
53
+
54
+ ```typescript
55
+ JWT.validate(string : string, options: DecodeOptions): Promise<Token>
56
+ ```
57
+
58
+ Returns a `Token` object if the given string is a valid (and trusted) JWT.
59
+ If validation fails, throws an `Error`.
60
+
61
+ Types of errors `JWT.validate()` can throw:
62
+ - Algorithm mismatch: If the token header's `alg` claim does not match the
63
+ configured algorithm (`options.algorithm`)
64
+ - Signature mismatch: If the signature does not match
65
+ - Expiration: If the token's `exp` claim is not acceptable according to policy
66
+
67
+ ```typescript
68
+ import { JWT } from '@astronautlabs/jwt';
69
+
70
+ try {
71
+ let token = await JWT.validate(`eY...`, { algorithm: 'HS256', secretOrKey: 'stuff' });
72
+ console.dir(token); // => { string: 'eY...', claims: { sub: ..., ... } }
73
+ } catch (e) {
74
+ console.error('Failed to validate token: ');
75
+ console.error(e);
76
+ }
77
+ ```
78
+
79
+ ### Expiration
80
+
81
+ You can configure a policy for built-in validation of the `exp` claim when validating tokens.
82
+ To do so, specify `{ validate: { exp: "(policyName)" }}` within the `options` passed to `JWT.validate()`.
83
+
84
+ The available policies are:
85
+ - `when-present` (default) -- When a token has an `exp` claim, fail validation if the token is expired
86
+ - `force` -- Require tokens to have a valid (fresh) `exp` claim
87
+ - `ignore` -- Ignore `exp` even when it is present (it will still be available on `token.claims`).
88
+
89
+ You can override the current time by providing `options.now`. Consider using this instead
90
+ of `options.validate.exp = 'ignore'`.
91
+
92
+ ### Options
93
+
94
+ - `validate`
95
+ * `exp` -- Expiration policy. For more see [Expiration](#expiration)
96
+
97
+ # Supported Platforms
98
+ - **Browser/Web** using WebCrypto
99
+ - **Node.js**
100
+
101
+ # Supported Algorithms
102
+ - `HS256`
103
+ - `HS384`
104
+ - `HS512`
105
+ - `RS256`
106
+ - `RS512`
107
+ - `ES256`
package/demo.key ADDED
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEogIBAAKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWw
3
+ kWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mr
4
+ m/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEi
5
+ NQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV
6
+ 3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2
7
+ QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQABAoIBACiARq2wkltjtcjs
8
+ kFvZ7w1JAORHbEufEO1Eu27zOIlqbgyAcAl7q+/1bip4Z/x1IVES84/yTaM8p0go
9
+ amMhvgry/mS8vNi1BN2SAZEnb/7xSxbflb70bX9RHLJqKnp5GZe2jexw+wyXlwaM
10
+ +bclUCrh9e1ltH7IvUrRrQnFJfh+is1fRon9Co9Li0GwoN0x0byrrngU8Ak3Y6D9
11
+ D8GjQA4Elm94ST3izJv8iCOLSDBmzsPsXfcCUZfmTfZ5DbUDMbMxRnSo3nQeoKGC
12
+ 0Lj9FkWcfmLcpGlSXTO+Ww1L7EGq+PT3NtRae1FZPwjddQ1/4V905kyQFLamAA5Y
13
+ lSpE2wkCgYEAy1OPLQcZt4NQnQzPz2SBJqQN2P5u3vXl+zNVKP8w4eBv0vWuJJF+
14
+ hkGNnSxXQrTkvDOIUddSKOzHHgSg4nY6K02ecyT0PPm/UZvtRpWrnBjcEVtHEJNp
15
+ bU9pLD5iZ0J9sbzPU/LxPmuAP2Bs8JmTn6aFRspFrP7W0s1Nmk2jsm0CgYEAyH0X
16
+ +jpoqxj4efZfkUrg5GbSEhf+dZglf0tTOA5bVg8IYwtmNk/pniLG/zI7c+GlTc9B
17
+ BwfMr59EzBq/eFMI7+LgXaVUsM/sS4Ry+yeK6SJx/otIMWtDfqxsLD8CPMCRvecC
18
+ 2Pip4uSgrl0MOebl9XKp57GoaUWRWRHqwV4Y6h8CgYAZhI4mh4qZtnhKjY4TKDjx
19
+ QYufXSdLAi9v3FxmvchDwOgn4L+PRVdMwDNms2bsL0m5uPn104EzM6w1vzz1zwKz
20
+ 5pTpPI0OjgWN13Tq8+PKvm/4Ga2MjgOgPWQkslulO/oMcXbPwWC3hcRdr9tcQtn9
21
+ Imf9n2spL/6EDFId+Hp/7QKBgAqlWdiXsWckdE1Fn91/NGHsc8syKvjjk1onDcw0
22
+ NvVi5vcba9oGdElJX3e9mxqUKMrw7msJJv1MX8LWyMQC5L6YNYHDfbPF1q5L4i8j
23
+ 8mRex97UVokJQRRA452V2vCO6S5ETgpnad36de3MUxHgCOX3qL382Qx9/THVmbma
24
+ 3YfRAoGAUxL/Eu5yvMK8SAt/dJK6FedngcM3JEFNplmtLYVLWhkIlNRGDwkg3I5K
25
+ y18Ae9n7dHVueyslrb6weq7dTkYDi3iOYRW8HRkIQh06wEdbxt0shTzAJvvCQfrB
26
+ jg/3747WSsf/zBTcHihTRBdAv6OmdhV4/dD5YBfLAkLrd+mX7iE=
27
+ -----END RSA PRIVATE KEY-----
package/demo8.key ADDED
@@ -0,0 +1,28 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCfPKKzVmN80HRs
3
+ GAoUxK++RO3CW8GxomrtLnAD6TN5U5WlVbCRZ1WFrizfxcz+lr/Kvjtq/v7PdVOa
4
+ 8NHIAdxpP3bCFEQWku/1yPmVN4lKJvKv8yub9i2MJlVaBo5giHCtfAouo+v/XWKd
5
+ awCR8jK28dZPFlgRxcuABcW5S5pLe4X2ASI1DDMZNTW/QWqSpMGvgHydbccI3jtd
6
+ S7S3xjR76V/izg7FBrBYPv0n3/l3dHLS9tXcCbUW0YmIm87BGwh9UKEOlhK1NwdM
7
+ Iyq29ZtXovXUFaSnMZdJbge/jepr4ZJg4PZBTrwxvn2hKTY4H4G04ukmh+ZsYQaC
8
+ +bDIIj0zAgMBAAECggEAKIBGrbCSW2O1yOyQW9nvDUkA5EdsS58Q7US7bvM4iWpu
9
+ DIBwCXur7/VuKnhn/HUhURLzj/JNozynSChqYyG+CvL+ZLy82LUE3ZIBkSdv/vFL
10
+ Ft+VvvRtf1EcsmoqenkZl7aN7HD7DJeXBoz5tyVQKuH17WW0fsi9StGtCcUl+H6K
11
+ zV9Gif0Kj0uLQbCg3THRvKuueBTwCTdjoP0PwaNADgSWb3hJPeLMm/yII4tIMGbO
12
+ w+xd9wJRl+ZN9nkNtQMxszFGdKjedB6goYLQuP0WRZx+YtykaVJdM75bDUvsQar4
13
+ 9Pc21Fp7UVk/CN11DX/hX3TmTJAUtqYADliVKkTbCQKBgQDLU48tBxm3g1CdDM/P
14
+ ZIEmpA3Y/m7e9eX7M1Uo/zDh4G/S9a4kkX6GQY2dLFdCtOS8M4hR11Io7MceBKDi
15
+ djorTZ5zJPQ8+b9Rm+1GlaucGNwRW0cQk2ltT2ksPmJnQn2xvM9T8vE+a4A/YGzw
16
+ mZOfpoVGykWs/tbSzU2aTaOybQKBgQDIfRf6OmirGPh59l+RSuDkZtISF/51mCV/
17
+ S1M4DltWDwhjC2Y2T+meIsb/Mjtz4aVNz0EHB8yvn0TMGr94Uwjv4uBdpVSwz+xL
18
+ hHL7J4rpInH+i0gxa0N+rGwsPwI8wJG95wLY+Kni5KCuXQw55uX1cqnnsahpRZFZ
19
+ EerBXhjqHwKBgBmEjiaHipm2eEqNjhMoOPFBi59dJ0sCL2/cXGa9yEPA6Cfgv49F
20
+ V0zAM2azZuwvSbm4+fXTgTMzrDW/PPXPArPmlOk8jQ6OBY3XdOrz48q+b/gZrYyO
21
+ A6A9ZCSyW6U7+gxxds/BYLeFxF2v21xC2f0iZ/2faykv/oQMUh34en/tAoGACqVZ
22
+ 2JexZyR0TUWf3X80YexzyzIq+OOTWicNzDQ29WLm9xtr2gZ0SUlfd72bGpQoyvDu
23
+ awkm/UxfwtbIxALkvpg1gcN9s8XWrkviLyPyZF7H3tRWiQlBFEDjnZXa8I7pLkRO
24
+ Cmdp3fp17cxTEeAI5feovfzZDH39MdWZuZrdh9ECgYBTEv8S7nK8wrxIC390kroV
25
+ 52eBwzckQU2mWa0thUtaGQiU1EYPCSDcjkrLXwB72ft0dW57KyWtvrB6rt1ORgOL
26
+ eI5hFbwdGQhCHTrAR1vG3SyFPMAm+8JB+sGOD/fvjtZKx//MFNweKFNEF0C/o6Z2
27
+ FXj90PlgF8sCQut36ZfuIQ==
28
+ -----END PRIVATE KEY-----
@@ -0,0 +1,4 @@
1
+ export declare class Base64URL {
2
+ static stringify(a: any): string;
3
+ static parse(s: any): Uint8Array;
4
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Base64URL = void 0;
4
+ var Base64URL = /** @class */ (function () {
5
+ function Base64URL() {
6
+ }
7
+ Base64URL.stringify = function (a) {
8
+ var base64string = btoa(String.fromCharCode.apply(0, a));
9
+ return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
10
+ };
11
+ Base64URL.parse = function (s) {
12
+ s = s.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '');
13
+ return new Uint8Array(Array.prototype.map.call(atob(s), function (c) { return c.charCodeAt(0); }));
14
+ };
15
+ return Base64URL;
16
+ }());
17
+ exports.Base64URL = Base64URL;
18
+ //# sourceMappingURL=base64url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base64url.js","sourceRoot":"","sources":["../../src/browser/base64url.ts"],"names":[],"mappings":";;;AACA;IAAA;IAUA,CAAC;IATiB,mBAAS,GAAvB,UAAwB,CAAC;QACrB,IAAI,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACzD,OAAO,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAClF,CAAC;IAEa,eAAK,GAAnB,UAAoB,CAAC;QACjB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC/D,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAf,CAAe,CAAC,CAAC,CAAC;IACnF,CAAC;IACL,gBAAC;AAAD,CAAC,AAVD,IAUC;AAVY,8BAAS"}
@@ -0,0 +1,5 @@
1
+ import { JWTEngine } from '../common';
2
+ export * from '../common';
3
+ export * from './webcrypto-jwt';
4
+ export declare function createJWTEngine(): JWTEngine;
5
+ export declare const JWT: JWTEngine;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.JWT = exports.createJWTEngine = void 0;
14
+ var webcrypto_jwt_1 = require("./webcrypto-jwt");
15
+ __exportStar(require("../common"), exports);
16
+ __exportStar(require("./webcrypto-jwt"), exports);
17
+ function createJWTEngine() { return new webcrypto_jwt_1.WebCryptoJWT(); }
18
+ exports.createJWTEngine = createJWTEngine;
19
+ ;
20
+ exports.JWT = createJWTEngine();
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;AACA,iDAA+C;AAC/C,4CAA0B;AAC1B,kDAAgC;AAChC,SAAgB,eAAe,KAAiB,OAAO,IAAI,4BAAY,EAAE,CAAC,CAAC,CAAC;AAA5E,0CAA4E;AAAA,CAAC;AAChE,QAAA,GAAG,GAAG,eAAe,EAAE,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare class Utils {
2
+ static isString(s: any): boolean;
3
+ static utf8ToUint8Array(str: any): Uint8Array;
4
+ static isFunction(fn: any): boolean;
5
+ static isObject(arg: any): boolean;
6
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Utils = void 0;
4
+ var base64url_1 = require("./base64url");
5
+ var Utils = /** @class */ (function () {
6
+ function Utils() {
7
+ }
8
+ Utils.isString = function (s) {
9
+ return typeof s === 'string';
10
+ };
11
+ Utils.utf8ToUint8Array = function (str) {
12
+ str = btoa(unescape(encodeURIComponent(str)));
13
+ return base64url_1.Base64URL.parse(str);
14
+ };
15
+ Utils.isFunction = function (fn) {
16
+ return typeof fn === 'function';
17
+ };
18
+ Utils.isObject = function (arg) {
19
+ return arg !== null && typeof arg === 'object';
20
+ };
21
+ return Utils;
22
+ }());
23
+ exports.Utils = Utils;
24
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/browser/utils.ts"],"names":[],"mappings":";;;AAAA,yCAAwC;AAExC;IAAA;IAiBA,CAAC;IAhBiB,cAAQ,GAAtB,UAAuB,CAAC;QACpB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC;IACjC,CAAC;IAEa,sBAAgB,GAA9B,UAA+B,GAAG;QAC9B,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9C,OAAO,qBAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAEa,gBAAU,GAAxB,UAAyB,EAAE;QACvB,OAAO,OAAO,EAAE,KAAK,UAAU,CAAC;IACpC,CAAC;IAEa,cAAQ,GAAtB,UAAuB,GAAG;QACtB,OAAO,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC;IACnD,CAAC;IACL,YAAC;AAAD,CAAC,AAjBD,IAiBC;AAjBY,sBAAK"}
@@ -0,0 +1,22 @@
1
+ import { JWTEngine, EncodeOptions, Token, DecodeOptions } from "../common/interface";
2
+ export declare class WebCryptoJWT implements JWTEngine {
3
+ private subtleCrypto?;
4
+ constructor(subtleCrypto?: SubtleCrypto);
5
+ decodeUntrusted(token: string): Promise<Token>;
6
+ private findSubtleCrypto;
7
+ encode(payload: Record<string, any>, options: EncodeOptions): Promise<Token>;
8
+ validate(string: string, options: DecodeOptions): Promise<Token>;
9
+ private algorithmOf;
10
+ private str2ab;
11
+ /**
12
+ * Adapted from https://chromium.googlesource.com/chromium/blink/+/master/LayoutTests/crypto/subtle/hmac/sign-verify.html
13
+ *
14
+ * @param token
15
+ * @param secret
16
+ * @param alg
17
+ */
18
+ private _verify;
19
+ private _sign;
20
+ private _decode;
21
+ private _decodeBase64URL;
22
+ }
@@ -0,0 +1,378 @@
1
+ "use strict";
2
+ // Originally from https://github.com/pose/webcrypto-jwt
3
+ // (C) Copyright (c) 2015 Alberto Pose albertopose@gmail.com
4
+ // Used under the terms of the MIT License (https://github.com/pose/webcrypto-jwt/blob/master/LICENSE.md)
5
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
+ return new (P || (P = Promise))(function (resolve, reject) {
8
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
11
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
12
+ });
13
+ };
14
+ var __generator = (this && this.__generator) || function (thisArg, body) {
15
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
16
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
17
+ function verb(n) { return function (v) { return step([n, v]); }; }
18
+ function step(op) {
19
+ if (f) throw new TypeError("Generator is already executing.");
20
+ while (_) try {
21
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
22
+ if (y = 0, t) op = [op[0] & 2, t.value];
23
+ switch (op[0]) {
24
+ case 0: case 1: t = op; break;
25
+ case 4: _.label++; return { value: op[1], done: false };
26
+ case 5: _.label++; y = op[1]; op = [0]; continue;
27
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
28
+ default:
29
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
30
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
31
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
32
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
33
+ if (t[2]) _.ops.pop();
34
+ _.trys.pop(); continue;
35
+ }
36
+ op = body.call(thisArg, _);
37
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
38
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
39
+ }
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.WebCryptoJWT = void 0;
43
+ var base64url_1 = require("./base64url");
44
+ var utils_1 = require("./utils");
45
+ var common_1 = require("../common");
46
+ var ALGORITHMS = {
47
+ none: {},
48
+ HS256: {
49
+ importKey: {
50
+ name: 'HMAC',
51
+ hash: 'SHA-256'
52
+ },
53
+ operation: {
54
+ name: 'HMAC',
55
+ hash: 'SHA-256'
56
+ }
57
+ },
58
+ HS384: {
59
+ importKey: {
60
+ name: 'HMAC',
61
+ hash: 'SHA-384'
62
+ },
63
+ operation: {
64
+ name: 'HMAC',
65
+ hash: 'SHA-384'
66
+ }
67
+ },
68
+ HS512: {
69
+ importKey: {
70
+ name: 'HMAC',
71
+ hash: 'SHA-512'
72
+ },
73
+ operation: {
74
+ name: 'HMAC',
75
+ hash: 'SHA-512'
76
+ }
77
+ },
78
+ RS256: {
79
+ importKey: {
80
+ name: 'RSASSA-PKCS1-v1_5',
81
+ hash: 'SHA-256'
82
+ },
83
+ operation: {
84
+ name: 'RSASSA-PKCS1-v1_5',
85
+ hash: 'SHA-256'
86
+ }
87
+ },
88
+ RS512: {
89
+ importKey: {
90
+ name: 'RSASSA-PKCS1-v1_5',
91
+ hash: 'SHA-512'
92
+ },
93
+ operation: {
94
+ name: 'RSASSA-PKCS1-v1_5',
95
+ hash: 'SHA-512'
96
+ }
97
+ },
98
+ ES256: {
99
+ importKey: {
100
+ name: 'ECDSA',
101
+ namedCurve: 'P-256'
102
+ },
103
+ operation: {
104
+ name: 'ECDSA',
105
+ namedCurve: 'P-256',
106
+ hash: 'SHA-256'
107
+ }
108
+ }
109
+ };
110
+ var WebCryptoJWT = /** @class */ (function () {
111
+ function WebCryptoJWT(subtleCrypto) {
112
+ this.subtleCrypto = subtleCrypto;
113
+ if (!subtleCrypto)
114
+ this.findSubtleCrypto();
115
+ }
116
+ WebCryptoJWT.prototype.decodeUntrusted = function (token) {
117
+ return __awaiter(this, void 0, void 0, function () {
118
+ var decodedToken;
119
+ return __generator(this, function (_a) {
120
+ decodedToken = this._decode(token);
121
+ return [2 /*return*/, { claims: decodedToken.payload, string: token }];
122
+ });
123
+ });
124
+ };
125
+ WebCryptoJWT.prototype.findSubtleCrypto = function () {
126
+ if ('crypto' in window)
127
+ this.subtleCrypto = crypto.subtle || crypto['webkitSubtle'];
128
+ if (!this.subtleCrypto && 'msCrypto' in window)
129
+ this.subtleCrypto = window['msCrypto'].Subtle;
130
+ };
131
+ WebCryptoJWT.prototype.encode = function (payload, options) {
132
+ return __awaiter(this, void 0, void 0, function () {
133
+ var _a;
134
+ return __generator(this, function (_b) {
135
+ switch (_b.label) {
136
+ case 0:
137
+ _a = {};
138
+ return [4 /*yield*/, this._sign(payload, options.secretOrKey, this.algorithmOf(options))];
139
+ case 1: return [2 /*return*/, (_a.string = _b.sent(),
140
+ _a.claims = payload,
141
+ _a)];
142
+ }
143
+ });
144
+ });
145
+ };
146
+ WebCryptoJWT.prototype.validate = function (string, options) {
147
+ var _a;
148
+ return __awaiter(this, void 0, void 0, function () {
149
+ var decodedToken, algorithm, secretOrKey, claims, _b;
150
+ return __generator(this, function (_c) {
151
+ switch (_c.label) {
152
+ case 0:
153
+ decodedToken = this._decode(string);
154
+ algorithm = this.algorithmOf(options);
155
+ secretOrKey = options.secretOrKey;
156
+ claims = decodedToken.payload;
157
+ // Signature must match
158
+ if (decodedToken.header.alg !== algorithm)
159
+ throw new Error("Cannot validate JWT '" + string + "': Token has incorrect algorithm");
160
+ _b = algorithm !== 'none';
161
+ if (!_b) return [3 /*break*/, 2];
162
+ return [4 /*yield*/, this._verify(decodedToken, secretOrKey, algorithm)];
163
+ case 1:
164
+ _b = !(_c.sent());
165
+ _c.label = 2;
166
+ case 2:
167
+ if (_b)
168
+ throw new Error("Cannot validate JWT '" + string + "': Invalid signature");
169
+ // Algorithm must match
170
+ // Expiration
171
+ try {
172
+ common_1.validateExpiry(claims.exp, options.now, (_a = options.validate) === null || _a === void 0 ? void 0 : _a.exp);
173
+ }
174
+ catch (e) {
175
+ throw new Error("Cannot validate JWT '" + string + "': " + e.message);
176
+ }
177
+ return [2 /*return*/, {
178
+ string: string,
179
+ claims: decodedToken.payload
180
+ }];
181
+ }
182
+ });
183
+ });
184
+ };
185
+ WebCryptoJWT.prototype.algorithmOf = function (options) {
186
+ return options.algorithm || 'HS256';
187
+ };
188
+ WebCryptoJWT.prototype.str2ab = function (str) {
189
+ var buf = new ArrayBuffer(str.length);
190
+ var bufView = new Uint8Array(buf);
191
+ for (var i = 0, strLen = str.length; i < strLen; i++) {
192
+ bufView[i] = str.charCodeAt(i);
193
+ }
194
+ return buf;
195
+ };
196
+ /**
197
+ * Adapted from https://chromium.googlesource.com/chromium/blink/+/master/LayoutTests/crypto/subtle/hmac/sign-verify.html
198
+ *
199
+ * @param token
200
+ * @param secret
201
+ * @param alg
202
+ */
203
+ WebCryptoJWT.prototype._verify = function (token, secret, alg) {
204
+ return __awaiter(this, void 0, void 0, function () {
205
+ var importAlgorithm, keyFormat, secretBuf, encoder, key, e_1, identifier, partialToken, signaturePart, messageAsUint8Array, signatureAsUint8Array, e_2;
206
+ return __generator(this, function (_a) {
207
+ switch (_a.label) {
208
+ case 0:
209
+ if (alg === 'none')
210
+ return [2 /*return*/, true];
211
+ importAlgorithm = ALGORITHMS[alg];
212
+ if (!importAlgorithm)
213
+ throw new Error("Algorithm " + alg + " is not supported");
214
+ encoder = new TextEncoder();
215
+ // TODO Test utf8ToUint8Array function
216
+ if (secret.includes('-----BEGIN PUBLIC KEY-----')) {
217
+ secretBuf = this.str2ab(atob(secret
218
+ .replace(/^-----BEGIN PUBLIC KEY-----\n/, '')
219
+ .replace(/\n-----END PUBLIC KEY-----/, '')
220
+ .replace(/\n/g, '')));
221
+ keyFormat = 'spki';
222
+ }
223
+ else if (secret.includes('-----BEGIN RSA PUBLIC KEY-----')) {
224
+ throw new Error("PKCS#1 keys are not supported. "
225
+ + "Please convert the key to PKCS#8 instead: "
226
+ + "openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pkcs1.key -out pkcs8.key");
227
+ }
228
+ else {
229
+ secretBuf = encoder.encode(secret);
230
+ keyFormat = 'raw';
231
+ }
232
+ if (!this.subtleCrypto)
233
+ throw new Error("Not supported: No Subtle Crypto support");
234
+ _a.label = 1;
235
+ case 1:
236
+ _a.trys.push([1, 3, , 4]);
237
+ return [4 /*yield*/, this.subtleCrypto.importKey(keyFormat, secretBuf, importAlgorithm.importKey, false, ['verify'])];
238
+ case 2:
239
+ key = _a.sent();
240
+ return [3 /*break*/, 4];
241
+ case 3:
242
+ e_1 = _a.sent();
243
+ identifier = "jwtUncaughtError" + Math.floor(10000 + Math.random() * 10000);
244
+ console.error("JWT.verify(): Caught error while importing " + alg + " key: format=" + keyFormat + ", importAlgorithm: " + JSON.stringify(importAlgorithm.importKey) + ".");
245
+ console.error(e_1);
246
+ if (typeof window !== 'undefined') {
247
+ window[identifier] = e_1;
248
+ console.error("To aid in debugging, this error was saved to " + identifier);
249
+ }
250
+ throw e_1;
251
+ case 4:
252
+ partialToken = token.encodedHeader + "." + token.encodedPayload;
253
+ signaturePart = token.signature;
254
+ messageAsUint8Array = encoder.encode(partialToken);
255
+ signatureAsUint8Array = base64url_1.Base64URL.parse(signaturePart);
256
+ if (!this.subtleCrypto)
257
+ throw new Error("Not supported: No Subtle Crypto support");
258
+ _a.label = 5;
259
+ case 5:
260
+ _a.trys.push([5, 7, , 8]);
261
+ return [4 /*yield*/, this.subtleCrypto.verify(importAlgorithm.operation, key, signatureAsUint8Array, messageAsUint8Array)];
262
+ case 6: return [2 /*return*/, _a.sent()];
263
+ case 7:
264
+ e_2 = _a.sent();
265
+ console.error("JWT.verify(): Caught error while verifying token:");
266
+ console.error(e_2);
267
+ throw e_2;
268
+ case 8: return [2 /*return*/];
269
+ }
270
+ });
271
+ });
272
+ };
273
+ ;
274
+ WebCryptoJWT.prototype._sign = function (payload, secret, alg) {
275
+ return __awaiter(this, void 0, void 0, function () {
276
+ var importAlgorithm, payloadAsJSON, header, headerAsJSON, partialToken, keyFormat, encoder, secretBuf, key, e_3, messageAsUint8Array, signature, e_4, signatureAsBase64, token;
277
+ return __generator(this, function (_a) {
278
+ switch (_a.label) {
279
+ case 0:
280
+ importAlgorithm = ALGORITHMS[alg];
281
+ if (!importAlgorithm)
282
+ throw new Error("Algorithm '" + alg + "' is not supported");
283
+ payloadAsJSON = JSON.stringify(payload);
284
+ header = { alg: alg, typ: 'JWT' };
285
+ headerAsJSON = JSON.stringify(header);
286
+ partialToken = base64url_1.Base64URL.stringify(utils_1.Utils.utf8ToUint8Array(headerAsJSON)) + '.' +
287
+ base64url_1.Base64URL.stringify(utils_1.Utils.utf8ToUint8Array(payloadAsJSON));
288
+ if (alg === 'none')
289
+ return [2 /*return*/, partialToken + "."];
290
+ keyFormat = 'raw';
291
+ encoder = new TextEncoder();
292
+ // TODO Test utf8ToUint8Array function
293
+ if (secret.includes('-----BEGIN RSA PRIVATE KEY-----')) {
294
+ throw new Error("PKCS#1 keys are not supported. Please convert the key to PKCS#8 instead: openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pkcs1.key -out pkcs8.key");
295
+ }
296
+ else if (secret.includes('-----BEGIN PRIVATE KEY-----')) {
297
+ secretBuf = this.str2ab(atob(secret
298
+ .replace(/^-----BEGIN PRIVATE KEY-----\n/, '')
299
+ .replace(/\n-----END PRIVATE KEY-----/, '')
300
+ .replace(/\n/g, '')));
301
+ keyFormat = 'pkcs8';
302
+ }
303
+ else {
304
+ secretBuf = encoder.encode(secret);
305
+ }
306
+ if (!this.subtleCrypto)
307
+ throw new Error("Not supported: No Subtle Crypto support");
308
+ _a.label = 1;
309
+ case 1:
310
+ _a.trys.push([1, 3, , 4]);
311
+ return [4 /*yield*/, this.subtleCrypto.importKey(keyFormat, secretBuf, importAlgorithm.importKey, false, ['sign'])];
312
+ case 2:
313
+ key = _a.sent();
314
+ return [3 /*break*/, 4];
315
+ case 3:
316
+ e_3 = _a.sent();
317
+ console.error("JWT.sign(): Caught error while importing " + alg + " key: format=" + keyFormat + ", importAlgorithm: " + JSON.stringify(importAlgorithm.importKey));
318
+ console.error(e_3);
319
+ throw e_3;
320
+ case 4:
321
+ messageAsUint8Array = utils_1.Utils.utf8ToUint8Array(partialToken);
322
+ if (!this.subtleCrypto)
323
+ throw new Error("Not supported: No Subtle Crypto support");
324
+ _a.label = 5;
325
+ case 5:
326
+ _a.trys.push([5, 7, , 8]);
327
+ return [4 /*yield*/, this.subtleCrypto.sign(importAlgorithm.operation, key, messageAsUint8Array)];
328
+ case 6:
329
+ signature = _a.sent();
330
+ return [3 /*break*/, 8];
331
+ case 7:
332
+ e_4 = _a.sent();
333
+ console.error("JWT.sign(): Caught error while signing token:");
334
+ console.error(e_4);
335
+ throw e_4;
336
+ case 8:
337
+ signatureAsBase64 = base64url_1.Base64URL.stringify(new Uint8Array(signature));
338
+ token = partialToken + "." + signatureAsBase64;
339
+ return [2 /*return*/, token];
340
+ }
341
+ });
342
+ });
343
+ };
344
+ ;
345
+ WebCryptoJWT.prototype._decode = function (token) {
346
+ var parts = token.split('.');
347
+ if (parts.length !== 3)
348
+ throw new Error("Invalid token '" + token + "': must have 3 parts separated by '.'");
349
+ return {
350
+ encodedHeader: parts[0],
351
+ encodedPayload: parts[1],
352
+ signature: parts[2],
353
+ header: JSON.parse(this._decodeBase64URL(parts[0])),
354
+ payload: JSON.parse(this._decodeBase64URL(parts[1])),
355
+ };
356
+ };
357
+ ;
358
+ WebCryptoJWT.prototype._decodeBase64URL = function (string) {
359
+ string = string.replace(/-/g, '+').replace(/_/g, '/');
360
+ switch (string.length % 4) {
361
+ case 0:
362
+ break;
363
+ case 2:
364
+ string += '==';
365
+ break;
366
+ case 3:
367
+ string += '=';
368
+ break;
369
+ default:
370
+ throw new Error("Illegal Base64URL string '" + string + "'");
371
+ }
372
+ // TODO Use shim or document incompatible browsers
373
+ return decodeURIComponent(escape(atob(string)));
374
+ };
375
+ return WebCryptoJWT;
376
+ }());
377
+ exports.WebCryptoJWT = WebCryptoJWT;
378
+ //# sourceMappingURL=webcrypto-jwt.js.map