UNPKG

middy-middleware-jwt-auth

Version:

A middy JSON web token authorization middleware inspired by express-jwt.

182 lines 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isAuthorizedEvent = exports.isAuthOptions = exports.EncryptionAlgorithms = exports.JWTAuthMiddleware = void 0; var tslib_1 = require("tslib"); var debug_1 = tslib_1.__importDefault(require("debug")); var http_errors_1 = tslib_1.__importDefault(require("http-errors")); var jsonwebtoken_1 = tslib_1.__importStar(require("jsonwebtoken")); var IAuthOptions_1 = require("./interfaces/IAuthOptions"); Object.defineProperty(exports, "EncryptionAlgorithms", { enumerable: true, get: function () { return IAuthOptions_1.EncryptionAlgorithms; } }); Object.defineProperty(exports, "isAuthOptions", { enumerable: true, get: function () { return IAuthOptions_1.isAuthOptions; } }); var IAuthorizedEvent_1 = require("./interfaces/IAuthorizedEvent"); /** The actual middleware */ var JWTAuthMiddleware = /** @class */ (function () { /** Creates a new JWT Auth middleware */ function JWTAuthMiddleware(options) { var _this = this; this.options = options; /** * Checks for an authentication token, saves its content to event.auth and throws errors if anything fishy goes on. * It will pass if no authorization header is present, but will ensure that event.auth is undefined in those cases. * Authorization or authorization headers will both be checked. If both exist, the middleware will throw an error. * If options.tokenSource is set, then that function will be used to retrieve the token and Headers will serve as * fallback. * @param event - The event to check */ this.before = function (_a) { return tslib_1.__awaiter(_this, [_a], void 0, function (_b) { var token, payload, err_1; var _this = this; var event = _b.event; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: this.logger("Checking whether event.auth already is populated"); if (event && event.auth !== undefined) { this.logger("event.auth already populated, has to be empty"); throw (0, http_errors_1.default)(400, "The events auth property has to be empty", { type: "EventAuthNotEmpty", }); } return [4 /*yield*/, this.getTokenFromSource(event)]; case 1: token = (_c.sent()) || this.getTokenFromAuthHeader(event); if (token === undefined) { return [2 /*return*/]; } this.logger("Verifying authorization token"); _c.label = 2; case 2: _c.trys.push([2, 4, , 5]); return [4 /*yield*/, new Promise(function (resolve, reject) { jsonwebtoken_1.default.verify(token, _this.options.secretOrPublicKey, { algorithms: [_this.options.algorithm], }, function (err, decoded) { if (err) return reject(err); resolve(decoded); }); })]; case 3: payload = _c.sent(); return [3 /*break*/, 5]; case 4: err_1 = _c.sent(); this.logger("Token could not be verified"); if (err_1 instanceof jsonwebtoken_1.TokenExpiredError) { this.logger("Token expired at ".concat(new Date(err_1.expiredAt).toUTCString())); throw (0, http_errors_1.default)(401, "Token expired at ".concat(new Date(err_1.expiredAt).toUTCString()), { expiredAt: err_1.expiredAt, type: "TokenExpiredError", }); } if (err_1 instanceof jsonwebtoken_1.NotBeforeError) { this.logger("Token not valid before ".concat(err_1.date)); throw (0, http_errors_1.default)(401, "Token not valid before ".concat(err_1.date), { date: err_1.date, type: "NotBeforeError", }); } throw (0, http_errors_1.default)(401, "Invalid token", { type: "InvalidToken", }); case 5: this.logger("Token verified"); if (this.options.isPayload !== undefined) { this.logger("Verifying token payload"); if (!this.options.isPayload(payload)) { this.logger("Token payload malformed, was ".concat(JSON.stringify(payload))); throw (0, http_errors_1.default)(400, "Token payload malformed, was ".concat(JSON.stringify(payload)), { payload: payload, type: "TokenPayloadMalformedError", }); } this.logger("Token payload valid"); event.auth = { payload: payload, token: token }; } else { event.auth = { payload: payload, token: token }; } return [2 /*return*/]; } }); }); }; this.logger = (0, debug_1.default)("middy-middleware-jwt-auth"); this.logger("Setting up JWTAuthMiddleware with encryption algorithm ".concat(this.options.algorithm)); } JWTAuthMiddleware.create = function (options) { if (!(0, IAuthOptions_1.isAuthOptions)(options)) { throw new TypeError("Expected IAuthOptions, received ".concat(JSON.stringify(options), " instead")); } return new JWTAuthMiddleware(options); }; /** Extracts a token from an authorization header. */ JWTAuthMiddleware.prototype.getTokenFromAuthHeader = function (event) { this.logger("Checking whether event contains authorization header"); if (!(0, IAuthorizedEvent_1.isAuthorizedEvent)(event)) { this.logger("No authorization header found"); if (this.options.credentialsRequired) { throw (0, http_errors_1.default)(401, "No valid bearer token was set in the authorization header", { type: "AuthenticationRequired", }); } return; } this.logger("Checking whether event contains multiple authorization headers"); if ((0, IAuthorizedEvent_1.isLowerCaseAuthorizedEvent)(event) && (0, IAuthorizedEvent_1.isUpperCaseAuthorizedEvent)(event)) { this.logger("Both authorization and Authorization headers found, only one can be set"); throw (0, http_errors_1.default)(400, "Both authorization and Authorization headers found, only one can be set", { type: "MultipleAuthorizationHeadersSet", }); } this.logger("One authorization header found"); this.logger("Checking whether authorization header is formed correctly"); var normalizedAuth = typeof event.headers.authorization === "string" ? event.headers.authorization : event.headers.Authorization; var authHeader = Array.isArray(normalizedAuth) ? normalizedAuth[0] : normalizedAuth; var parts = authHeader.split(" "); if (parts.length !== 2 || parts[0] !== "Bearer") { this.logger("Authorization header malformed, it was \"".concat(authHeader, "\" but should be of format \"Bearer token\"")); throw (0, http_errors_1.default)(401, "Format should be \"Authorization: Bearer [token]\", received \"Authorization: ".concat(authHeader, "\" instead"), { type: "WrongAuthFormat", }); } this.logger("Authorization header formed correctly"); return parts[1]; }; /** Extracts a token from a source defined in the options. */ JWTAuthMiddleware.prototype.getTokenFromSource = function (event) { return tslib_1.__awaiter(this, void 0, void 0, function () { var tokenSource, _a; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: this.logger("Checking whether event contains token based on given tokenSource"); tokenSource = this.options.tokenSource; if (!tokenSource) { return [2 /*return*/, undefined]; } _b.label = 1; case 1: _b.trys.push([1, 3, , 4]); return [4 /*yield*/, tokenSource(event)]; case 2: return [2 /*return*/, _b.sent()]; case 3: _a = _b.sent(); return [2 /*return*/, undefined]; case 4: return [2 /*return*/]; } }); }); }; return JWTAuthMiddleware; }()); exports.JWTAuthMiddleware = JWTAuthMiddleware; exports.default = JWTAuthMiddleware.create; var IAuthorizedEvent_2 = require("./interfaces/IAuthorizedEvent"); Object.defineProperty(exports, "isAuthorizedEvent", { enumerable: true, get: function () { return IAuthorizedEvent_2.isAuthorizedEvent; } }); //# sourceMappingURL=JWTAuthMiddleware.js.map