import { readFileSync } from 'fs';
import { execSync } from 'child_process';
import jwt from 'jsonwebtoken';
import readlineSync from 'readline-sync';
const getUserInput = () => {
const tenantId = readlineSync.question('Please enter your tenant ID: ');
const clientId = readlineSync.question('Please enter your client ID: ');
return { tenantId, clientId };
};
const readPrivateKey = (path) => {
try {
return readFileSync(path, 'utf8');
} catch (error) {
console.error(`Error reading private key from ${path}:`, error);
throw error;
}
};
const getX5tThumbprint = (certPath) => {
const command = `echo $(openssl x509 -in ${certPath} -fingerprint -noout) | sed 's/SHA1 Fingerprint=//g' | sed 's/://g' | xxd -r -ps | base64`;
try {
const thumbprint = execSync(command).toString().trim();
return thumbprint;
} catch (error) {
console.error(`Error calculating x5t thumbprint for certificate ${certPath}:`, error);
throw error;
}
};
const TEN_YEARS_MS = 10 * 365 * 24 * 60 * 60 * 1000;
// Microsoft Entra ID doesn't place restrictions on the exp time currently.
const createJwtClaims = (tenantId, clientId, expirationInSeconds = TEN_YEARS_MS) => ({
aud: `https://login.microsoftonline.com/${tenantId}/oauth2/token`,
iss: clientId,
sub: clientId,
nbf: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + expirationInSeconds,
jti: generateUniqueJti(),
});
const generateUniqueJti = () => `jti-${Math.random().toString(36).substr(2, 9)}`;
const createJwt = (claims, privateKey, x5tThumbprint) => {
const header = {
alg: "PS256",
typ: "JWT",
x5t: x5tThumbprint,
};
try {
return jwt.sign(claims, privateKey, {
algorithm: 'RS256',
header: header,
});
} catch (error) {
console.error('Error signing JWT:', error);
throw error;
}
};
const generateJwtAssertion = () => {
const { tenantId, clientId } = getUserInput();
const certPath = 'certificate.pem';
const privateKeyPath = 'private.key';
const privateKey = readPrivateKey(privateKeyPath);
const x5tThumbprint = getX5tThumbprint(certPath);
console.log('Calculated x5t Thumbprint:', x5tThumbprint);
const claims = createJwtClaims(tenantId, clientId);
const token = createJwt(claims, privateKey, x5tThumbprint);
console.log('JWT Assertion:', token);
};
generateJwtAssertion();