@twin.org/web 0.0.1-next.36 → 0.0.1-next.37
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/dist/cjs/index.cjs +78 -85
- package/dist/esm/index.mjs +79 -86
- package/dist/types/index.d.ts +2 -1
- package/dist/types/models/IJwk.d.ts +2 -58
- package/dist/types/models/IJwtHeader.d.ts +2 -18
- package/dist/types/models/IJwtPayload.d.ts +2 -33
- package/dist/types/models/jwkCryptoKey.d.ts +5 -0
- package/dist/types/utils/jwk.d.ts +13 -0
- package/dist/types/utils/jwt.d.ts +28 -23
- package/docs/changelog.md +1 -1
- package/docs/reference/classes/Jwk.md +35 -0
- package/docs/reference/classes/Jwt.md +45 -57
- package/docs/reference/index.md +2 -2
- package/docs/reference/interfaces/IJwk.md +2 -106
- package/docs/reference/interfaces/IJwtHeader.md +4 -24
- package/docs/reference/interfaces/IJwtPayload.md +4 -56
- package/docs/reference/type-aliases/JwkCryptoKey.md +5 -0
- package/locales/en.json +5 -1
- package/package.json +5 -4
- package/dist/types/models/jwtAlgorithms.d.ts +0 -17
- package/docs/reference/type-aliases/JwtAlgorithms.md +0 -5
- package/docs/reference/variables/JwtAlgorithms.md +0 -19
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var core = require('@twin.org/core');
|
|
4
|
-
var
|
|
4
|
+
var jose = require('jose');
|
|
5
5
|
|
|
6
6
|
// Copyright 2024 IOTA Stiftung.
|
|
7
7
|
// SPDX-License-Identifier: Apache-2.0.
|
|
@@ -345,23 +345,6 @@ const HttpStatusCode = {
|
|
|
345
345
|
networkAuthenticationRequired: 511
|
|
346
346
|
};
|
|
347
347
|
|
|
348
|
-
// Copyright 2024 IOTA Stiftung.
|
|
349
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
350
|
-
/**
|
|
351
|
-
* The cryptographic algorithms supported for JSON Web Tokens and JSON Web Keys.
|
|
352
|
-
*/
|
|
353
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
354
|
-
const JwtAlgorithms = {
|
|
355
|
-
/**
|
|
356
|
-
* HMAC using SHA-256.
|
|
357
|
-
*/
|
|
358
|
-
HS256: "HS256",
|
|
359
|
-
/**
|
|
360
|
-
* EdDSA using Ed25519.
|
|
361
|
-
*/
|
|
362
|
-
EdDSA: "EdDSA"
|
|
363
|
-
};
|
|
364
|
-
|
|
365
348
|
// Copyright 2024 IOTA Stiftung.
|
|
366
349
|
// SPDX-License-Identifier: Apache-2.0.
|
|
367
350
|
/**
|
|
@@ -714,7 +697,34 @@ class FetchHelper {
|
|
|
714
697
|
// Copyright 2024 IOTA Stiftung.
|
|
715
698
|
// SPDX-License-Identifier: Apache-2.0.
|
|
716
699
|
/**
|
|
717
|
-
* Class to
|
|
700
|
+
* Class to handle JSON Web Keys.
|
|
701
|
+
*/
|
|
702
|
+
class Jwk {
|
|
703
|
+
/**
|
|
704
|
+
* Runtime name for the class.
|
|
705
|
+
* @internal
|
|
706
|
+
*/
|
|
707
|
+
static _CLASS_NAME = "Jwk";
|
|
708
|
+
/**
|
|
709
|
+
* Convert the JWK to a crypto key.
|
|
710
|
+
* @param jwk The JWK to convert.
|
|
711
|
+
* @returns The crypto key.
|
|
712
|
+
*/
|
|
713
|
+
static async toCryptoKey(jwk) {
|
|
714
|
+
core.Guards.object(Jwk._CLASS_NAME, "jwk", jwk);
|
|
715
|
+
try {
|
|
716
|
+
return jose.importJWK(jwk);
|
|
717
|
+
}
|
|
718
|
+
catch (err) {
|
|
719
|
+
throw new core.GeneralError(Jwk._CLASS_NAME, "jwkImportFailed", undefined, err);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// Copyright 2024 IOTA Stiftung.
|
|
725
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
726
|
+
/**
|
|
727
|
+
* Class to handle JSON Web Tokens.
|
|
718
728
|
*/
|
|
719
729
|
class Jwt {
|
|
720
730
|
/**
|
|
@@ -731,9 +741,9 @@ class Jwt {
|
|
|
731
741
|
*/
|
|
732
742
|
static async encode(header, payload, key) {
|
|
733
743
|
core.Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
734
|
-
core.Guards.
|
|
744
|
+
core.Guards.stringValue(Jwt._CLASS_NAME, "header.alg", header.alg);
|
|
735
745
|
core.Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
736
|
-
core.Guards.
|
|
746
|
+
core.Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
737
747
|
return Jwt.internalEncode(header, payload, key);
|
|
738
748
|
}
|
|
739
749
|
/**
|
|
@@ -745,7 +755,7 @@ class Jwt {
|
|
|
745
755
|
*/
|
|
746
756
|
static async encodeWithSigner(header, payload, signer) {
|
|
747
757
|
core.Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
748
|
-
core.Guards.
|
|
758
|
+
core.Guards.stringValue(Jwt._CLASS_NAME, "header.alg", header.alg);
|
|
749
759
|
core.Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
750
760
|
core.Guards.function(Jwt._CLASS_NAME, "signer", signer);
|
|
751
761
|
return Jwt.internalEncode(header, payload, undefined, signer);
|
|
@@ -792,13 +802,8 @@ class Jwt {
|
|
|
792
802
|
*/
|
|
793
803
|
static async verify(token, key) {
|
|
794
804
|
core.Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
795
|
-
core.Guards.
|
|
796
|
-
|
|
797
|
-
const verified = await Jwt.verifySignature(decoded.header, decoded.payload, decoded.signature, key);
|
|
798
|
-
return {
|
|
799
|
-
verified,
|
|
800
|
-
...decoded
|
|
801
|
-
};
|
|
805
|
+
core.Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
806
|
+
return Jwt.verifySignature(token, key);
|
|
802
807
|
}
|
|
803
808
|
/**
|
|
804
809
|
* Verify a token.
|
|
@@ -809,79 +814,75 @@ class Jwt {
|
|
|
809
814
|
static async verifyWithVerifier(token, verifier) {
|
|
810
815
|
core.Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
811
816
|
core.Guards.function(Jwt._CLASS_NAME, "verifier", verifier);
|
|
812
|
-
|
|
813
|
-
const decoded = await Jwt.decode(token);
|
|
814
|
-
const verified = await Jwt.verifySignature(decoded.header, decoded.payload, decoded.signature, undefined, verifier);
|
|
815
|
-
return {
|
|
816
|
-
verified,
|
|
817
|
-
...decoded
|
|
818
|
-
};
|
|
817
|
+
return Jwt.verifySignature(token, undefined, verifier);
|
|
819
818
|
}
|
|
820
819
|
/**
|
|
821
820
|
* Verify a token by parts.
|
|
822
|
-
* @param
|
|
823
|
-
* @param payload The payload to verify.
|
|
824
|
-
* @param signature The signature to verify.
|
|
821
|
+
* @param token The token to verify.
|
|
825
822
|
* @param key The key for verifying the token, if not provided no verification occurs.
|
|
826
823
|
* @param verifier Custom verification method.
|
|
827
824
|
* @returns True if the parts are verified.
|
|
828
825
|
*/
|
|
829
|
-
static async verifySignature(
|
|
826
|
+
static async verifySignature(token, key, verifier) {
|
|
827
|
+
core.Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
830
828
|
const hasKey = core.Is.notEmpty(key);
|
|
831
829
|
const hasVerifier = core.Is.notEmpty(verifier);
|
|
832
830
|
if (!hasKey && !hasVerifier) {
|
|
833
831
|
throw new core.GeneralError(Jwt._CLASS_NAME, "noKeyOrVerifier");
|
|
834
832
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
core.Is.object(payload) &&
|
|
838
|
-
core.Is.uint8Array(signature) &&
|
|
839
|
-
core.Is.arrayOneOf(header.alg, Object.values(JwtAlgorithms))) {
|
|
840
|
-
const segments = [];
|
|
841
|
-
const headerBytes = core.Converter.utf8ToBytes(JSON.stringify(header));
|
|
842
|
-
segments.push(core.Converter.bytesToBase64Url(headerBytes));
|
|
843
|
-
const payloadBytes = core.Converter.utf8ToBytes(JSON.stringify(payload));
|
|
844
|
-
segments.push(core.Converter.bytesToBase64Url(payloadBytes));
|
|
845
|
-
const jwtHeaderAndPayload = core.Converter.utf8ToBytes(segments.join("."));
|
|
846
|
-
verifier ??= async (alg, k, p, s) => Jwt.defaultVerifier(alg, k, p, s);
|
|
847
|
-
verified = await verifier(header.alg, key, jwtHeaderAndPayload, signature);
|
|
848
|
-
}
|
|
849
|
-
return verified;
|
|
833
|
+
verifier ??= async (t, k) => Jwt.defaultVerifier(t, k);
|
|
834
|
+
return verifier(token, key);
|
|
850
835
|
}
|
|
851
836
|
/**
|
|
852
837
|
* The default signer for the JWT.
|
|
853
838
|
* @param alg The algorithm to use.
|
|
854
839
|
* @param key The key to sign with.
|
|
840
|
+
* @param header The header to sign.
|
|
855
841
|
* @param payload The payload to sign.
|
|
856
842
|
* @returns The signature.
|
|
857
843
|
*/
|
|
858
|
-
static async defaultSigner(alg, key, payload) {
|
|
859
|
-
core.Guards.
|
|
860
|
-
core.Guards.
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
844
|
+
static async defaultSigner(alg, key, header, payload) {
|
|
845
|
+
core.Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
846
|
+
core.Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
847
|
+
core.Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
848
|
+
const signer = new jose.SignJWT(payload);
|
|
849
|
+
header.alg = alg;
|
|
850
|
+
signer.setProtectedHeader(header);
|
|
851
|
+
if (alg === "EdDSA" && core.Is.uint8Array(key)) {
|
|
852
|
+
// crypto.subtle.importKey does not support Ed25519 keys in raw format.
|
|
853
|
+
// We need to convert the key to PKCS8 format before importing.
|
|
854
|
+
// The PKCS8 format is the raw key prefixed with the ASN.1 sequence for an Ed25519 private key.
|
|
855
|
+
// The ASN.1 sequence is 48 46 02 01 00 30 05 06 03 2b 65 70 04 20 04 20
|
|
856
|
+
const pkcs8Prefix = new Uint8Array([
|
|
857
|
+
48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32
|
|
858
|
+
]); // 0x302e020100300506032b657004220420
|
|
859
|
+
const pkcs8PrivateKey = core.Uint8ArrayHelper.concat([pkcs8Prefix, key]);
|
|
860
|
+
const imported = await crypto.subtle.importKey("pkcs8", pkcs8PrivateKey, "Ed25519", false, [
|
|
861
|
+
"sign"
|
|
862
|
+
]);
|
|
863
|
+
return signer.sign(imported);
|
|
864
864
|
}
|
|
865
|
-
return
|
|
865
|
+
return signer.sign(key);
|
|
866
866
|
}
|
|
867
867
|
/**
|
|
868
868
|
* The default verifier for the JWT.
|
|
869
|
-
* @param
|
|
869
|
+
* @param token The token to verify.
|
|
870
870
|
* @param key The key to verify with.
|
|
871
|
-
* @param payload The payload to verify.
|
|
872
|
-
* @param signature The signature to verify.
|
|
873
871
|
* @returns True if the signature was verified.
|
|
874
872
|
*/
|
|
875
|
-
static async defaultVerifier(
|
|
876
|
-
core.Guards.
|
|
877
|
-
core.Guards.
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
873
|
+
static async defaultVerifier(token, key) {
|
|
874
|
+
core.Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
875
|
+
core.Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
876
|
+
try {
|
|
877
|
+
const result = await jose.jwtVerify(token, key);
|
|
878
|
+
return {
|
|
879
|
+
header: result.protectedHeader,
|
|
880
|
+
payload: result.payload
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
catch (err) {
|
|
884
|
+
throw new core.GeneralError(Jwt._CLASS_NAME, "verifyFailed", undefined, err);
|
|
883
885
|
}
|
|
884
|
-
return crypto.Ed25519.verify(key, payload, signature);
|
|
885
886
|
}
|
|
886
887
|
/**
|
|
887
888
|
* Encode a token.
|
|
@@ -898,19 +899,11 @@ class Jwt {
|
|
|
898
899
|
if (!hasKey && !hasSigner) {
|
|
899
900
|
throw new core.GeneralError(Jwt._CLASS_NAME, "noKeyOrSigner");
|
|
900
901
|
}
|
|
901
|
-
signer ??= async (alg, k, p) => Jwt.defaultSigner(alg, k, p);
|
|
902
|
+
signer ??= async (alg, k, h, p) => Jwt.defaultSigner(alg, k, h, p);
|
|
902
903
|
if (core.Is.undefined(header.typ)) {
|
|
903
904
|
header.typ = "JWT";
|
|
904
905
|
}
|
|
905
|
-
|
|
906
|
-
const headerBytes = core.Converter.utf8ToBytes(JSON.stringify(header));
|
|
907
|
-
segments.push(core.Converter.bytesToBase64Url(headerBytes));
|
|
908
|
-
const payloadBytes = core.Converter.utf8ToBytes(JSON.stringify(payload));
|
|
909
|
-
segments.push(core.Converter.bytesToBase64Url(payloadBytes));
|
|
910
|
-
const jwtHeaderAndPayload = core.Converter.utf8ToBytes(segments.join("."));
|
|
911
|
-
const sigBytes = await signer(header.alg, key, jwtHeaderAndPayload);
|
|
912
|
-
segments.push(core.Converter.bytesToBase64Url(sigBytes));
|
|
913
|
-
return segments.join(".");
|
|
906
|
+
return signer(header.alg, key, header, payload);
|
|
914
907
|
}
|
|
915
908
|
}
|
|
916
909
|
|
|
@@ -1055,7 +1048,7 @@ exports.FetchHelper = FetchHelper;
|
|
|
1055
1048
|
exports.HeaderTypes = HeaderTypes;
|
|
1056
1049
|
exports.HttpMethod = HttpMethod;
|
|
1057
1050
|
exports.HttpStatusCode = HttpStatusCode;
|
|
1051
|
+
exports.Jwk = Jwk;
|
|
1058
1052
|
exports.Jwt = Jwt;
|
|
1059
|
-
exports.JwtAlgorithms = JwtAlgorithms;
|
|
1060
1053
|
exports.MimeTypeHelper = MimeTypeHelper;
|
|
1061
1054
|
exports.MimeTypes = MimeTypes;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseError, StringHelper, Guards, Is, AsyncCache, ObjectHelper,
|
|
2
|
-
import {
|
|
1
|
+
import { BaseError, StringHelper, Guards, Is, AsyncCache, ObjectHelper, GeneralError, Converter, Uint8ArrayHelper } from '@twin.org/core';
|
|
2
|
+
import { importJWK, SignJWT, jwtVerify } from 'jose';
|
|
3
3
|
|
|
4
4
|
// Copyright 2024 IOTA Stiftung.
|
|
5
5
|
// SPDX-License-Identifier: Apache-2.0.
|
|
@@ -343,23 +343,6 @@ const HttpStatusCode = {
|
|
|
343
343
|
networkAuthenticationRequired: 511
|
|
344
344
|
};
|
|
345
345
|
|
|
346
|
-
// Copyright 2024 IOTA Stiftung.
|
|
347
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
348
|
-
/**
|
|
349
|
-
* The cryptographic algorithms supported for JSON Web Tokens and JSON Web Keys.
|
|
350
|
-
*/
|
|
351
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
352
|
-
const JwtAlgorithms = {
|
|
353
|
-
/**
|
|
354
|
-
* HMAC using SHA-256.
|
|
355
|
-
*/
|
|
356
|
-
HS256: "HS256",
|
|
357
|
-
/**
|
|
358
|
-
* EdDSA using Ed25519.
|
|
359
|
-
*/
|
|
360
|
-
EdDSA: "EdDSA"
|
|
361
|
-
};
|
|
362
|
-
|
|
363
346
|
// Copyright 2024 IOTA Stiftung.
|
|
364
347
|
// SPDX-License-Identifier: Apache-2.0.
|
|
365
348
|
/**
|
|
@@ -712,7 +695,34 @@ class FetchHelper {
|
|
|
712
695
|
// Copyright 2024 IOTA Stiftung.
|
|
713
696
|
// SPDX-License-Identifier: Apache-2.0.
|
|
714
697
|
/**
|
|
715
|
-
* Class to
|
|
698
|
+
* Class to handle JSON Web Keys.
|
|
699
|
+
*/
|
|
700
|
+
class Jwk {
|
|
701
|
+
/**
|
|
702
|
+
* Runtime name for the class.
|
|
703
|
+
* @internal
|
|
704
|
+
*/
|
|
705
|
+
static _CLASS_NAME = "Jwk";
|
|
706
|
+
/**
|
|
707
|
+
* Convert the JWK to a crypto key.
|
|
708
|
+
* @param jwk The JWK to convert.
|
|
709
|
+
* @returns The crypto key.
|
|
710
|
+
*/
|
|
711
|
+
static async toCryptoKey(jwk) {
|
|
712
|
+
Guards.object(Jwk._CLASS_NAME, "jwk", jwk);
|
|
713
|
+
try {
|
|
714
|
+
return importJWK(jwk);
|
|
715
|
+
}
|
|
716
|
+
catch (err) {
|
|
717
|
+
throw new GeneralError(Jwk._CLASS_NAME, "jwkImportFailed", undefined, err);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Copyright 2024 IOTA Stiftung.
|
|
723
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
724
|
+
/**
|
|
725
|
+
* Class to handle JSON Web Tokens.
|
|
716
726
|
*/
|
|
717
727
|
class Jwt {
|
|
718
728
|
/**
|
|
@@ -729,9 +739,9 @@ class Jwt {
|
|
|
729
739
|
*/
|
|
730
740
|
static async encode(header, payload, key) {
|
|
731
741
|
Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
732
|
-
Guards.
|
|
742
|
+
Guards.stringValue(Jwt._CLASS_NAME, "header.alg", header.alg);
|
|
733
743
|
Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
734
|
-
Guards.
|
|
744
|
+
Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
735
745
|
return Jwt.internalEncode(header, payload, key);
|
|
736
746
|
}
|
|
737
747
|
/**
|
|
@@ -743,7 +753,7 @@ class Jwt {
|
|
|
743
753
|
*/
|
|
744
754
|
static async encodeWithSigner(header, payload, signer) {
|
|
745
755
|
Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
746
|
-
Guards.
|
|
756
|
+
Guards.stringValue(Jwt._CLASS_NAME, "header.alg", header.alg);
|
|
747
757
|
Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
748
758
|
Guards.function(Jwt._CLASS_NAME, "signer", signer);
|
|
749
759
|
return Jwt.internalEncode(header, payload, undefined, signer);
|
|
@@ -790,13 +800,8 @@ class Jwt {
|
|
|
790
800
|
*/
|
|
791
801
|
static async verify(token, key) {
|
|
792
802
|
Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
793
|
-
Guards.
|
|
794
|
-
|
|
795
|
-
const verified = await Jwt.verifySignature(decoded.header, decoded.payload, decoded.signature, key);
|
|
796
|
-
return {
|
|
797
|
-
verified,
|
|
798
|
-
...decoded
|
|
799
|
-
};
|
|
803
|
+
Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
804
|
+
return Jwt.verifySignature(token, key);
|
|
800
805
|
}
|
|
801
806
|
/**
|
|
802
807
|
* Verify a token.
|
|
@@ -807,79 +812,75 @@ class Jwt {
|
|
|
807
812
|
static async verifyWithVerifier(token, verifier) {
|
|
808
813
|
Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
809
814
|
Guards.function(Jwt._CLASS_NAME, "verifier", verifier);
|
|
810
|
-
|
|
811
|
-
const decoded = await Jwt.decode(token);
|
|
812
|
-
const verified = await Jwt.verifySignature(decoded.header, decoded.payload, decoded.signature, undefined, verifier);
|
|
813
|
-
return {
|
|
814
|
-
verified,
|
|
815
|
-
...decoded
|
|
816
|
-
};
|
|
815
|
+
return Jwt.verifySignature(token, undefined, verifier);
|
|
817
816
|
}
|
|
818
817
|
/**
|
|
819
818
|
* Verify a token by parts.
|
|
820
|
-
* @param
|
|
821
|
-
* @param payload The payload to verify.
|
|
822
|
-
* @param signature The signature to verify.
|
|
819
|
+
* @param token The token to verify.
|
|
823
820
|
* @param key The key for verifying the token, if not provided no verification occurs.
|
|
824
821
|
* @param verifier Custom verification method.
|
|
825
822
|
* @returns True if the parts are verified.
|
|
826
823
|
*/
|
|
827
|
-
static async verifySignature(
|
|
824
|
+
static async verifySignature(token, key, verifier) {
|
|
825
|
+
Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
828
826
|
const hasKey = Is.notEmpty(key);
|
|
829
827
|
const hasVerifier = Is.notEmpty(verifier);
|
|
830
828
|
if (!hasKey && !hasVerifier) {
|
|
831
829
|
throw new GeneralError(Jwt._CLASS_NAME, "noKeyOrVerifier");
|
|
832
830
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
Is.object(payload) &&
|
|
836
|
-
Is.uint8Array(signature) &&
|
|
837
|
-
Is.arrayOneOf(header.alg, Object.values(JwtAlgorithms))) {
|
|
838
|
-
const segments = [];
|
|
839
|
-
const headerBytes = Converter.utf8ToBytes(JSON.stringify(header));
|
|
840
|
-
segments.push(Converter.bytesToBase64Url(headerBytes));
|
|
841
|
-
const payloadBytes = Converter.utf8ToBytes(JSON.stringify(payload));
|
|
842
|
-
segments.push(Converter.bytesToBase64Url(payloadBytes));
|
|
843
|
-
const jwtHeaderAndPayload = Converter.utf8ToBytes(segments.join("."));
|
|
844
|
-
verifier ??= async (alg, k, p, s) => Jwt.defaultVerifier(alg, k, p, s);
|
|
845
|
-
verified = await verifier(header.alg, key, jwtHeaderAndPayload, signature);
|
|
846
|
-
}
|
|
847
|
-
return verified;
|
|
831
|
+
verifier ??= async (t, k) => Jwt.defaultVerifier(t, k);
|
|
832
|
+
return verifier(token, key);
|
|
848
833
|
}
|
|
849
834
|
/**
|
|
850
835
|
* The default signer for the JWT.
|
|
851
836
|
* @param alg The algorithm to use.
|
|
852
837
|
* @param key The key to sign with.
|
|
838
|
+
* @param header The header to sign.
|
|
853
839
|
* @param payload The payload to sign.
|
|
854
840
|
* @returns The signature.
|
|
855
841
|
*/
|
|
856
|
-
static async defaultSigner(alg, key, payload) {
|
|
857
|
-
Guards.
|
|
858
|
-
Guards.
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
842
|
+
static async defaultSigner(alg, key, header, payload) {
|
|
843
|
+
Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
844
|
+
Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
845
|
+
Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
846
|
+
const signer = new SignJWT(payload);
|
|
847
|
+
header.alg = alg;
|
|
848
|
+
signer.setProtectedHeader(header);
|
|
849
|
+
if (alg === "EdDSA" && Is.uint8Array(key)) {
|
|
850
|
+
// crypto.subtle.importKey does not support Ed25519 keys in raw format.
|
|
851
|
+
// We need to convert the key to PKCS8 format before importing.
|
|
852
|
+
// The PKCS8 format is the raw key prefixed with the ASN.1 sequence for an Ed25519 private key.
|
|
853
|
+
// The ASN.1 sequence is 48 46 02 01 00 30 05 06 03 2b 65 70 04 20 04 20
|
|
854
|
+
const pkcs8Prefix = new Uint8Array([
|
|
855
|
+
48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32
|
|
856
|
+
]); // 0x302e020100300506032b657004220420
|
|
857
|
+
const pkcs8PrivateKey = Uint8ArrayHelper.concat([pkcs8Prefix, key]);
|
|
858
|
+
const imported = await crypto.subtle.importKey("pkcs8", pkcs8PrivateKey, "Ed25519", false, [
|
|
859
|
+
"sign"
|
|
860
|
+
]);
|
|
861
|
+
return signer.sign(imported);
|
|
862
862
|
}
|
|
863
|
-
return
|
|
863
|
+
return signer.sign(key);
|
|
864
864
|
}
|
|
865
865
|
/**
|
|
866
866
|
* The default verifier for the JWT.
|
|
867
|
-
* @param
|
|
867
|
+
* @param token The token to verify.
|
|
868
868
|
* @param key The key to verify with.
|
|
869
|
-
* @param payload The payload to verify.
|
|
870
|
-
* @param signature The signature to verify.
|
|
871
869
|
* @returns True if the signature was verified.
|
|
872
870
|
*/
|
|
873
|
-
static async defaultVerifier(
|
|
874
|
-
Guards.
|
|
875
|
-
Guards.
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
871
|
+
static async defaultVerifier(token, key) {
|
|
872
|
+
Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
873
|
+
Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
874
|
+
try {
|
|
875
|
+
const result = await jwtVerify(token, key);
|
|
876
|
+
return {
|
|
877
|
+
header: result.protectedHeader,
|
|
878
|
+
payload: result.payload
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
catch (err) {
|
|
882
|
+
throw new GeneralError(Jwt._CLASS_NAME, "verifyFailed", undefined, err);
|
|
881
883
|
}
|
|
882
|
-
return Ed25519.verify(key, payload, signature);
|
|
883
884
|
}
|
|
884
885
|
/**
|
|
885
886
|
* Encode a token.
|
|
@@ -896,19 +897,11 @@ class Jwt {
|
|
|
896
897
|
if (!hasKey && !hasSigner) {
|
|
897
898
|
throw new GeneralError(Jwt._CLASS_NAME, "noKeyOrSigner");
|
|
898
899
|
}
|
|
899
|
-
signer ??= async (alg, k, p) => Jwt.defaultSigner(alg, k, p);
|
|
900
|
+
signer ??= async (alg, k, h, p) => Jwt.defaultSigner(alg, k, h, p);
|
|
900
901
|
if (Is.undefined(header.typ)) {
|
|
901
902
|
header.typ = "JWT";
|
|
902
903
|
}
|
|
903
|
-
|
|
904
|
-
const headerBytes = Converter.utf8ToBytes(JSON.stringify(header));
|
|
905
|
-
segments.push(Converter.bytesToBase64Url(headerBytes));
|
|
906
|
-
const payloadBytes = Converter.utf8ToBytes(JSON.stringify(payload));
|
|
907
|
-
segments.push(Converter.bytesToBase64Url(payloadBytes));
|
|
908
|
-
const jwtHeaderAndPayload = Converter.utf8ToBytes(segments.join("."));
|
|
909
|
-
const sigBytes = await signer(header.alg, key, jwtHeaderAndPayload);
|
|
910
|
-
segments.push(Converter.bytesToBase64Url(sigBytes));
|
|
911
|
-
return segments.join(".");
|
|
904
|
+
return signer(header.alg, key, header, payload);
|
|
912
905
|
}
|
|
913
906
|
}
|
|
914
907
|
|
|
@@ -1048,4 +1041,4 @@ class MimeTypeHelper {
|
|
|
1048
1041
|
}
|
|
1049
1042
|
}
|
|
1050
1043
|
|
|
1051
|
-
export { FetchError, FetchHelper, HeaderTypes, HttpMethod, HttpStatusCode,
|
|
1044
|
+
export { FetchError, FetchHelper, HeaderTypes, HttpMethod, HttpStatusCode, Jwk, Jwt, MimeTypeHelper, MimeTypes };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,8 +7,9 @@ export * from "./models/IHttpHeaders";
|
|
|
7
7
|
export * from "./models/IJwk";
|
|
8
8
|
export * from "./models/IJwtHeader";
|
|
9
9
|
export * from "./models/IJwtPayload";
|
|
10
|
-
export * from "./models/
|
|
10
|
+
export * from "./models/jwkCryptoKey";
|
|
11
11
|
export * from "./models/mimeTypes";
|
|
12
12
|
export * from "./utils/fetchHelper";
|
|
13
|
+
export * from "./utils/jwk";
|
|
13
14
|
export * from "./utils/jwt";
|
|
14
15
|
export * from "./utils/mimeTypeHelper";
|
|
@@ -1,62 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { JWK } from "jose";
|
|
2
2
|
/**
|
|
3
3
|
* The fields in a JSON Web Key.
|
|
4
4
|
*/
|
|
5
|
-
export interface IJwk {
|
|
6
|
-
/**
|
|
7
|
-
* Additional fields in the key.
|
|
8
|
-
*/
|
|
9
|
-
[key: string]: unknown;
|
|
10
|
-
/**
|
|
11
|
-
* The cryptographic algorithm for the key.
|
|
12
|
-
*/
|
|
13
|
-
alg?: JwtAlgorithms;
|
|
14
|
-
/**
|
|
15
|
-
* The intended use for the key.
|
|
16
|
-
*/
|
|
17
|
-
use?: string;
|
|
18
|
-
/**
|
|
19
|
-
* The operation(s) that the key is intended to be used for.
|
|
20
|
-
*/
|
|
21
|
-
key_ops?: string[];
|
|
22
|
-
/**
|
|
23
|
-
* The key type parameter.
|
|
24
|
-
*/
|
|
25
|
-
kty: string;
|
|
26
|
-
/**
|
|
27
|
-
* The public key parameters.
|
|
28
|
-
*/
|
|
29
|
-
n?: string;
|
|
30
|
-
/**
|
|
31
|
-
* Exponent parameter.
|
|
32
|
-
*/
|
|
33
|
-
e?: string;
|
|
34
|
-
/**
|
|
35
|
-
* The private key parameters.
|
|
36
|
-
*/
|
|
37
|
-
d?: string;
|
|
38
|
-
/**
|
|
39
|
-
* The private key parameters.
|
|
40
|
-
*/
|
|
41
|
-
p?: string;
|
|
42
|
-
/**
|
|
43
|
-
* The private key parameters.
|
|
44
|
-
*/
|
|
45
|
-
q?: string;
|
|
46
|
-
/**
|
|
47
|
-
* The private key parameters.
|
|
48
|
-
*/
|
|
49
|
-
dp?: string;
|
|
50
|
-
/**
|
|
51
|
-
* The private key parameters.
|
|
52
|
-
*/
|
|
53
|
-
dq?: string;
|
|
54
|
-
/**
|
|
55
|
-
* The private key parameters.
|
|
56
|
-
*/
|
|
57
|
-
qi?: string;
|
|
58
|
-
/**
|
|
59
|
-
* The key ID.
|
|
60
|
-
*/
|
|
61
|
-
kid?: string;
|
|
5
|
+
export interface IJwk extends JWK {
|
|
62
6
|
}
|
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { JWTHeaderParameters } from "jose";
|
|
2
2
|
/**
|
|
3
3
|
* The fields in a JSON Web Token header.
|
|
4
4
|
*/
|
|
5
|
-
export interface IJwtHeader {
|
|
6
|
-
/**
|
|
7
|
-
* Additional fields in the header.
|
|
8
|
-
*/
|
|
9
|
-
[key: string]: unknown;
|
|
10
|
-
/**
|
|
11
|
-
* The type of the token.
|
|
12
|
-
*/
|
|
13
|
-
typ?: string;
|
|
14
|
-
/**
|
|
15
|
-
* The algorithm used to sign the token.
|
|
16
|
-
*/
|
|
17
|
-
alg: JwtAlgorithms;
|
|
18
|
-
/**
|
|
19
|
-
* The key ID.
|
|
20
|
-
*/
|
|
21
|
-
kid?: string;
|
|
5
|
+
export interface IJwtHeader extends JWTHeaderParameters {
|
|
22
6
|
}
|
|
@@ -1,37 +1,6 @@
|
|
|
1
|
+
import type { JWTPayload } from "jose";
|
|
1
2
|
/**
|
|
2
3
|
* The fields in a JSON Web Token payload.
|
|
3
4
|
*/
|
|
4
|
-
export interface IJwtPayload {
|
|
5
|
-
/**
|
|
6
|
-
* Additional fields in the payload.
|
|
7
|
-
*/
|
|
8
|
-
[key: string]: unknown;
|
|
9
|
-
/**
|
|
10
|
-
* The issuer of the token.
|
|
11
|
-
*/
|
|
12
|
-
iss?: string;
|
|
13
|
-
/**
|
|
14
|
-
* The subject of the token.
|
|
15
|
-
*/
|
|
16
|
-
sub?: string;
|
|
17
|
-
/**
|
|
18
|
-
* The audience of the token.
|
|
19
|
-
*/
|
|
20
|
-
aud?: string;
|
|
21
|
-
/**
|
|
22
|
-
* The expiration time of the token.
|
|
23
|
-
*/
|
|
24
|
-
exp?: number;
|
|
25
|
-
/**
|
|
26
|
-
* The not before time of the token.
|
|
27
|
-
*/
|
|
28
|
-
nbf?: number;
|
|
29
|
-
/**
|
|
30
|
-
* The issued at time of the token.
|
|
31
|
-
*/
|
|
32
|
-
iat?: number;
|
|
33
|
-
/**
|
|
34
|
-
* The JWT ID.
|
|
35
|
-
*/
|
|
36
|
-
jti?: string;
|
|
5
|
+
export interface IJwtPayload extends JWTPayload {
|
|
37
6
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IJwk } from "../models/IJwk";
|
|
2
|
+
import type { JwkCryptoKey } from "../models/jwkCryptoKey";
|
|
3
|
+
/**
|
|
4
|
+
* Class to handle JSON Web Keys.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Jwk {
|
|
7
|
+
/**
|
|
8
|
+
* Convert the JWK to a crypto key.
|
|
9
|
+
* @param jwk The JWK to convert.
|
|
10
|
+
* @returns The crypto key.
|
|
11
|
+
*/
|
|
12
|
+
static toCryptoKey(jwk: IJwk): Promise<JwkCryptoKey>;
|
|
13
|
+
}
|