UNPKG

middy-middleware-jwt-auth

Version:

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

150 lines 8.3 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; var event = _b.event; return tslib_1.__generator(this, function (_c) { 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", }); } token = this.getTokenFromSource(event) || this.getTokenFromAuthHeader(event); if (token === undefined) { return [2 /*return*/]; } this.logger("Verifying authorization token"); try { jsonwebtoken_1.default.verify(token, this.options.secretOrPublicKey, { algorithms: [this.options.algorithm], }); this.logger("Token verified"); } catch (err) { this.logger("Token could not be verified"); if (err instanceof jsonwebtoken_1.TokenExpiredError) { this.logger("Token expired at ".concat(new Date(err.expiredAt).toUTCString())); throw (0, http_errors_1.default)(401, "Token expired at ".concat(new Date(err.expiredAt).toUTCString()), { expiredAt: err.expiredAt, type: "TokenExpiredError", }); } if (err instanceof jsonwebtoken_1.NotBeforeError) { this.logger("Token not valid before ".concat(err.date)); throw (0, http_errors_1.default)(401, "Token not valid before ".concat(err.date), { date: err.date, type: "NotBeforeError", }); } throw (0, http_errors_1.default)(401, "Invalid token", { type: "InvalidToken", }); } payload = jsonwebtoken_1.default.decode(token); 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) { this.logger("Checking whether event contains token based on given tokenSource"); try { return this.options.tokenSource && this.options.tokenSource(event); } catch (err) { return undefined; } }; 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