UNPKG

@villedemontreal/jwt-validator

Version:
130 lines 5.38 kB
"use strict"; /* eslint-disable @typescript-eslint/only-throw-error */ Object.defineProperty(exports, "__esModule", { value: true }); exports.jwtValidator = void 0; const general_utils_1 = require("@villedemontreal/general-utils"); const jwt = require("jsonwebtoken"); const luxon_1 = require("luxon"); const constants_1 = require("./config/constants"); const customError_1 = require("./models/customError"); const jwtPayload_1 = require("./models/jwtPayload"); const publicKey_1 = require("./models/publicKey"); const cachedPublicKeyRepository_1 = require("./repositories/cachedPublicKeyRepository"); /** * JWT Validator */ class JwtValidator { async verifyAuthorizationHeader(header) { if (general_utils_1.utils.isBlank(header)) { throw (0, customError_1.createInvalidAuthHeaderError)({ code: constants_1.constants.errors.codes.NULL_VALUE, target: 'Authorization header', message: 'Empty Authorization header', }); } const parts = header.trim().split(' '); if (parts[0] !== 'Bearer') { throw (0, customError_1.createInvalidAuthHeaderError)({ code: constants_1.constants.errors.codes.INVALID_VALUE, target: 'Authorization header', message: 'Bad authentication scheme, "Bearer" required', }); } return await this.verifyToken(parts[1]); } async verifyToken(token) { const payload = this.parseJwt(token); const key = await this.getJwtPublicKey(payload); this.validateJwtCreationTimestamp(payload, key); this.validateJwtExpirationTimestamp(payload, key); return this.verifyJwt(token, key); } parseJwt(token) { const payload = jwt.decode(token); if (!payload) { throw (0, customError_1.createInvalidJwtError)({ code: constants_1.constants.errors.codes.INVALID_VALUE, target: 'jwt', message: 'jwt malformed', }); } return payload; } verifyJwt(token, publicKey) { let payload; try { payload = jwt.verify(token, publicKey.parsedPublicKey ?? publicKey.publicKey); } catch (err) { throw (0, customError_1.createInvalidJwtError)({ code: constants_1.constants.errors.codes.INVALID_VALUE, target: 'jwt', message: err.message, }); } if ((0, jwtPayload_1.isJWTPayload)(payload)) { return payload; } throw (0, customError_1.createInvalidJwtError)({ code: constants_1.constants.errors.codes.INVALID_VALUE, target: 'jwt', message: 'expected a valid JWT payload', }); } async getJwtPublicKey(payload) { const keyId = payload.keyId; if (!keyId || keyId <= 0) { throw (0, customError_1.createInvalidJwtError)({ code: constants_1.constants.errors.codes.INVALID_VALUE, target: 'jwt', message: 'missing public key ID', }); } const key = await cachedPublicKeyRepository_1.cachedPublicKeyRepository.getOne(keyId); // Check key state if (!key || key.state !== publicKey_1.PublicKeyState.ACTIVE) { throw (0, customError_1.createInvalidJwtError)({ code: constants_1.constants.errors.codes.INVALID_VALUE, target: 'jwt', message: 'this keyId is no longer active', }); } return key; } validateJwtCreationTimestamp(payload, key) { // Check the jwt was not created before the creation date of the key const payloadIat = luxon_1.DateTime.fromMillis(payload.iat * 1000).toUTC(); const keyCreatedAt = luxon_1.DateTime.fromISO(key.createdAt).toUTC(); if (payloadIat < keyCreatedAt) { throw (0, customError_1.createInvalidJwtError)({ code: constants_1.constants.errors.codes.INVALID_VALUE, target: 'jwt', message: "this jwt can't be created before the public key", }); } } validateJwtExpirationTimestamp(payload, key) { // Check expiration date if (key.expiresAt) { const keyexpiresAt = luxon_1.DateTime.fromISO(key.expiresAt).toUTC(); if (luxon_1.DateTime.utc() > keyexpiresAt) { throw (0, customError_1.createInvalidJwtError)({ code: constants_1.constants.errors.codes.INVALID_VALUE, target: 'jwt', message: 'this keyId is expired', }); } // Check the jwt was not created after the expiration date of the key const payloadIat = luxon_1.DateTime.fromMillis(payload.iat * 1000).toUTC(); if (payloadIat > keyexpiresAt) { throw (0, customError_1.createInvalidJwtError)({ code: constants_1.constants.errors.codes.INVALID_VALUE, target: 'jwt', message: "this jwt can't be created after the expiration of the public key", }); } } } } exports.jwtValidator = new JwtValidator(); //# sourceMappingURL=jwtValidator.js.map