@vdcs/jwt
Version:
JWT implementation in typescript
168 lines (162 loc) • 5.93 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// src/jwt.ts
import { base64urlDecode, base64urlEncode, uint8ArrayToBase64Url as uint8ArrayToBase64Url2 } from "@sd-jwt/utils";
// src/utils.ts
import { numberToBytesBE } from "@noble/curves/utils";
import { Base64 as Base642 } from "js-base64";
// src/key/p256.ts
import { p256 } from "@noble/curves/nist";
import { bytesToHex } from "@noble/curves/abstract/utils";
import { uint8ArrayToBase64Url } from "@sd-jwt/utils";
import { Base64 } from "js-base64";
var generateKeyPair = /* @__PURE__ */ __name(() => {
const privateKey = p256.utils.randomPrivateKey();
const publicKey = p256.getPublicKey(privateKey);
return {
privateKey,
publicKey
};
}, "generateKeyPair");
var privateKeyUint8ArrayToJwk = /* @__PURE__ */ __name((privateKeyBytes) => {
if (privateKeyBytes.length !== 32) {
throw new Error("Invalid private key length. Must be 32 bytes.");
}
const publicKeyBytes = p256.getPublicKey(privateKeyBytes, false);
const d = uint8ArrayToBase64Url(privateKeyBytes);
const x = uint8ArrayToBase64Url(publicKeyBytes.slice(1, 33));
const y = uint8ArrayToBase64Url(publicKeyBytes.slice(33, 65));
return {
kty: "EC",
crv: "P-256",
d,
x,
y
};
}, "privateKeyUint8ArrayToJwk");
var privateKeyJwkToUint8Array = /* @__PURE__ */ __name((jwk) => {
if (!jwk.d) {
throw new Error('Invalid private JWK: missing "d" parameter.');
}
const privateKeyBytes = Base64.toUint8Array(jwk.d);
if (privateKeyBytes.length !== 32) {
throw new Error('Invalid "d" parameter length. Must decode to 32 bytes.');
}
return privateKeyBytes;
}, "privateKeyJwkToUint8Array");
var publicKeyUint8ArrayToJwk = /* @__PURE__ */ __name((publicKeyBytes) => {
if (publicKeyBytes.length !== 33 && publicKeyBytes.length !== 65) {
throw new Error("Invalid public key length. Must be 33 (compressed) or 65 (uncompressed) bytes.");
}
const point = p256.Point.fromHex(bytesToHex(publicKeyBytes));
const x = uint8ArrayToBase64Url(bigIntTo32Bytes(point.x));
const y = uint8ArrayToBase64Url(bigIntTo32Bytes(point.y));
return {
kty: "EC",
crv: "P-256",
x,
y
};
}, "publicKeyUint8ArrayToJwk");
var publicKeyJwkToUint8Array = /* @__PURE__ */ __name((jwk, compressed = false) => {
const xBytes = Base64.toUint8Array(jwk.x);
const yBytes = Base64.toUint8Array(jwk.y);
const uncompressedPublicKey = new Uint8Array(65);
uncompressedPublicKey[0] = 4;
uncompressedPublicKey.set(xBytes, 1);
uncompressedPublicKey.set(yBytes, 33);
const point = p256.Point.fromHex(bytesToHex(uncompressedPublicKey));
return point.toRawBytes(compressed);
}, "publicKeyJwkToUint8Array");
var sign = /* @__PURE__ */ __name((data, privateKey) => {
const signature = p256.sign(data, privateKey);
return signature.toCompactRawBytes();
}, "sign");
var verify = /* @__PURE__ */ __name((msgHash, signature, publicKey) => {
return p256.verify(signature, msgHash, publicKey);
}, "verify");
var P256 = {
generateKeyPair,
privateKeyUint8ArrayToJwk,
privateKeyJwkToUint8Array,
publicKeyUint8ArrayToJwk,
publicKeyJwkToUint8Array,
sign,
verify
};
// src/utils.ts
var fromBase64Url = /* @__PURE__ */ __name((base64Url) => {
return Base642.toUint8Array(base64Url);
}, "fromBase64Url");
var bigIntTo32Bytes = /* @__PURE__ */ __name((num) => {
const bytes = numberToBytesBE(num, 32);
if (bytes.length > 32) {
throw new Error("BigInt is too large for 32 bytes.");
}
const padded = new Uint8Array(32);
padded.set(bytes, 32 - bytes.length);
return padded;
}, "bigIntTo32Bytes");
var normalizePrivateKey = /* @__PURE__ */ __name((privateKey) => {
if (privateKey instanceof Uint8Array) {
return privateKey;
}
if (!privateKey.d) {
throw new Error('Invalid private JWK: missing "d" parameter.');
}
return fromBase64Url(privateKey.d);
}, "normalizePrivateKey");
var normalizePublicKey = /* @__PURE__ */ __name((publicKey) => {
if (publicKey instanceof Uint8Array) {
return publicKey;
}
if (!publicKey.x || !publicKey.y) {
throw new Error('Invalid public JWK: missing "x" or "y" parameters.');
}
return P256.publicKeyJwkToUint8Array(publicKey);
}, "normalizePublicKey");
// src/jwt.ts
import { sha256 } from "@sd-jwt/hash";
import { Base64 as Base643 } from "js-base64";
var signJWT = /* @__PURE__ */ __name((options, privateKey) => {
const header = base64urlEncode(JSON.stringify(options.header));
const payload = base64urlEncode(JSON.stringify(options.payload));
const sigData = `${header}.${payload}`;
const normalizedPrivateKey = normalizePrivateKey(privateKey);
const signingInputBytes = sha256(sigData);
const signature = P256.sign(signingInputBytes, normalizedPrivateKey);
const base64UrlSignature = uint8ArrayToBase64Url2(signature);
return `${sigData}.${base64UrlSignature}`;
}, "signJWT");
var decodeJWT = /* @__PURE__ */ __name((compact) => {
try {
const [encodedHeader, encodedPayload] = compact.split(".");
const header = JSON.parse(base64urlDecode(encodedHeader));
const payload = JSON.parse(base64urlDecode(encodedPayload));
return {
header,
payload
};
} catch (e) {
throw new Error("Invalid JWT");
}
}, "decodeJWT");
var verifyJWT = /* @__PURE__ */ __name((compact, publicKey) => {
const [encodedHeader, encodedPayload, encodedSignature] = compact.split(".");
const normalizedPublicKey = normalizePublicKey(publicKey);
const signingInputBytes = sha256(`${encodedHeader}.${encodedPayload}`);
const result = P256.verify(signingInputBytes, Base643.toUint8Array(encodedSignature), normalizedPublicKey);
if (!result) {
throw new Error("Invalid signature");
}
return decodeJWT(compact);
}, "verifyJWT");
export {
P256,
bigIntTo32Bytes,
decodeJWT,
normalizePrivateKey,
normalizePublicKey,
signJWT,
verifyJWT
};