@eqxjs/azure-manage-identity
Version:
For get Azure keyvault secret
144 lines • 6.58 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyJWTToken = verifyJWTToken;
exports.verifyJWTTokenBySecret = verifyJWTTokenBySecret;
exports.signJWTToken = signJWTToken;
const keyvault_keys_1 = require("@azure/keyvault-keys");
const jwt = __importStar(require("jsonwebtoken"));
const confidential_mgnt_1 = require("../confidential.mgnt");
const secret_get_1 = require("../secret/secret.get");
const base64url_1 = __importDefault(require("base64url"));
const util_1 = require("util");
const node_crypto_1 = require("node:crypto");
const node_buffer_1 = require("node:buffer");
/**
* Converts a JWK (JSON Web Key) object to a PEM-encoded public key string
* using Node.js built-in crypto — no external library required.
*
* @param jwk - The JWK object to convert
* @returns PEM-encoded SPKI public key string
*/
function jwkToPem(jwk) {
const key = (0, node_crypto_1.createPublicKey)({ key: jwk, format: 'jwk' });
return key.export({ type: 'spki', format: 'pem' });
}
/**
* Verifies a JWT token using an Azure Key Vault key via cryptographic verification.
* The token's signature is verified using the SHA-256 digest of the header and payload.
*
* @param keyURL - The URL of the Azure Key Vault instance
* @param keyName - The name of the key to use for verification
* @param algorithm - The signing algorithm identifier (e.g. `'ES256'`)
* @param jwtToken - The JWT token string in `header.payload.signature` format
* @returns A promise resolving to a {@link VerifyResult} indicating success or failure
* @throws {Error} When the JWT token is not in a valid 3-part format
*/
async function verifyJWTToken(keyURL, keyName, algorithm, jwtToken) {
const credential = new confidential_mgnt_1.MyClientAssertionCredential();
const keysClient = new keyvault_keys_1.KeyClient(keyURL, credential);
const vaultKey = await keysClient.getKey(keyName);
const cryptographyClient = new keyvault_keys_1.CryptographyClient(vaultKey, credential);
const jwtArray = jwtToken.split('.');
if (jwtArray.length != 3) {
throw new Error(`Invalid JWT: ${jwtToken}`);
}
const signature = base64url_1.default.toBuffer(jwtArray[2]);
const data = (0, util_1.format)('%s.%s', jwtArray[0], jwtArray[1]);
const hash = (0, node_crypto_1.createHash)('sha256');
const digest = hash.update(data).digest();
return cryptographyClient.verify(algorithm, digest, signature);
}
/**
* Verifies a JWT token against a JWK set stored as a secret in Azure Key Vault.
* Iterates over all keys in the JWK set; returns `true` if any key validates the token.
*
* @param keyURL - The URL of the Azure Key Vault instance
* @param secretName - The name of the secret containing the JWK set as a JSON string
* @param jwtToken - The JWT token string to verify
* @returns A promise resolving to a {@link VerifyResult} with `result: true` on success
* @throws {Error} When all keys fail verification, or the secret is not a valid JWK set
*/
async function verifyJWTTokenBySecret(keyURL, secretName, jwtToken) {
const secret = await (0, secret_get_1.getSecret)(keyURL, secretName);
const returnCode = { result: false, keyID: '' };
returnCode.result = false;
const publicKey = JSON.parse(secret.value ?? '');
let lastError = '';
if (publicKey.keys && Array.isArray(publicKey.keys)) {
for (const i in publicKey.keys) {
try {
const pem = jwkToPem(publicKey.keys[i]);
jwt.verify(jwtToken, pem, { algorithms: ['RS256'] });
returnCode.result = true;
}
catch (error) {
lastError = `Verify token error ${error}`;
continue;
}
}
if (!returnCode.result) {
throw new Error(lastError);
}
}
else {
throw new Error(`Invalid public key: ${secret.value}`);
}
return returnCode;
}
/**
* Signs a payload using an Azure Key Vault key and returns a base64url-encoded signature.
* The payload is hashed with SHA-256 before signing.
*
* @param keyURL - The URL of the Azure Key Vault instance
* @param keyName - The name of the key to use for signing
* @param algorithm - The signing algorithm identifier (e.g. `'ES256'`)
* @param payload - The string payload to sign
* @returns A promise resolving to the base64url-encoded signature string
*/
async function signJWTToken(keyURL, keyName, algorithm, payload) {
const credential = new confidential_mgnt_1.MyClientAssertionCredential();
const keysClient = new keyvault_keys_1.KeyClient(keyURL, credential);
const vaultKey = await keysClient.getKey(keyName);
const cryptographyClient = new keyvault_keys_1.CryptographyClient(vaultKey, credential);
const hash = (0, node_crypto_1.createHash)('sha256');
const digest = hash.update(payload).digest();
const result = await cryptographyClient.sign(algorithm, digest);
return base64url_1.default.encode(node_buffer_1.Buffer.from(result.result));
}
//# sourceMappingURL=jwt.verify.js.map