middy-middleware-jwt-auth
Version:
A middy JSON web token authorization middleware inspired by express-jwt.
150 lines • 8.3 kB
JavaScript
"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