ysd-jwt
Version:
A secure and easy-to-use JWT library for Node.js and TypeScript.
81 lines (80 loc) • 3.08 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.sign = sign;
const crypto_1 = require("crypto");
const utils_1 = require("./utils");
const utils_2 = require("./utils");
const errors_1 = require("./errors");
/**
* Signs a JWT payload with the provided options
* @param payload - The JWT payload to sign
* @param options - Signing options including secret key and optional claims
* @returns The signed JWT token
* @throws {MissingKeyError} If secret/privateKey is missing or invalid
* @throws {ClaimValidationError} If payload contains invalid claims
*/
function sign(payload, options) {
const algorithm = options.algorithm || 'HS256';
// Validate key based on algorithm
if (algorithm === 'HS256') {
if (!options.secret) {
throw new errors_1.MissingKeyError('Secret is required for HS256 signing');
}
if (options.secret.length < 32) {
throw new errors_1.MissingKeyError('Secret must be at least 32 characters long');
}
}
else if (algorithm === 'RS256') {
if (!options.privateKey) {
throw new errors_1.MissingKeyError('Private key is required for RS256 signing');
}
(0, utils_1.validatePemKey)(options.privateKey, 'private');
}
// Validate payload
if (typeof payload !== 'object' || payload === null) {
throw new errors_1.ClaimValidationError('Payload must be a non-null object');
}
// Create header
const header = {
alg: algorithm,
typ: 'JWT',
...options.header, // Allow custom header fields
};
// Prepare payload
const now = Math.floor(Date.now() / 1000);
const finalPayload = { ...payload };
// Set standard claims
finalPayload.iat = now;
if (options.expiresIn) {
finalPayload.exp = now + (0, utils_2.parseExpiresIn)(options.expiresIn);
}
if (options.notBefore) {
finalPayload.nbf = now + (0, utils_2.parseExpiresIn)(options.notBefore);
}
if (options.issuer) {
finalPayload.iss = options.issuer;
}
if (options.audience) {
finalPayload.aud = options.audience;
}
if (options.jwtid) {
finalPayload.jti = options.jwtid;
}
// Encode header and payload
const encodedHeader = (0, utils_1.base64UrlEncode)(JSON.stringify(header));
const encodedPayload = (0, utils_1.base64UrlEncode)(JSON.stringify(finalPayload));
const signingInput = `${encodedHeader}.${encodedPayload}`;
// Create signature based on algorithm
let signature;
if (algorithm === 'HS256') {
signature = (0, crypto_1.createHmac)('sha256', options.secret).update(signingInput).digest();
}
else if (algorithm === 'RS256') {
signature = (0, crypto_1.createSign)('RSA-SHA256').update(signingInput).sign(options.privateKey);
}
else {
throw new errors_1.ClaimValidationError(`Unsupported algorithm: ${algorithm}`);
}
// Return final token
return `${encodedHeader}.${encodedPayload}.${(0, utils_1.base64UrlEncode)(signature)}`;
}