passport-fast-jwt
Version:
Passport authentication strategy for JSON Web Tokens using Fast-Jwt with support for EdDSA algorithm among others
155 lines (154 loc) • 6.86 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JwtStrategy = void 0;
const fast_jwt_1 = __importDefault(require("fast-jwt"));
const passport_strategy_1 = __importDefault(require("passport-strategy"));
/**
* @example
* ```typescript
* passport.use(new JwtStrategy(jwtVerifier, tokenExtractor, (sections, done, req) => {
* User.findOne({ id: sections.payload.sub }, (error, user) => {
* if (error) {
* return done(err, false)
* }
* if (!user) {
* return done(null, false, "User not found", 404)
* }
* return done(null, user)
* })
* }))
*
* // *-----------* OR *-----------*
*
* passport.use(new JwtStrategy(verifierOptions, tokenExtractor, (sections, done, req) => {
* User.findOne({ id: sections.payload.sub }, (error, user) => {
* if (error) {
* return done(err, false)
* }
* if (!user) {
* return done(null, false, "User not found", 404)
* }
* return done(null, user)
* })
* }))
* ```
*/
class JwtStrategy extends passport_strategy_1.default.Strategy {
constructor(...args) {
var _a;
super();
this.name = "jwt";
if (typeof args[0] === "function") {
this.verifyJwt = args[0];
}
else {
const _b = args[0], { key } = _b, opts = __rest(_b, ["key"]);
/**
* Just making TS happy here
*
* If algorithms is "none", the key must not be provided
*/
if ((_a = opts.algorithms) === null || _a === void 0 ? void 0 : _a.includes("none")) {
if (key) {
console.warn("Key was provided even though algorithms include none. Fast JWT says that if no algorithm is used, they key must not be provided. Thus the provided key parameter will be removed from verifier options");
}
this.verifyJwt = fast_jwt_1.default.createVerifier(Object.assign({}, opts));
}
else if (typeof key === "string" || key instanceof Buffer) {
this.verifyJwt = fast_jwt_1.default.createVerifier(Object.assign(Object.assign({}, opts), { key: key }));
}
else {
this.verifyJwt = fast_jwt_1.default.createVerifier(Object.assign(Object.assign({}, opts), { key: key }));
}
}
this.extractToken = args[1];
this.afterVerifiedCb = args[2];
}
createSections(sections) {
var _a, _b, _c, _d;
return {
header: (_a = sections === null || sections === void 0 ? void 0 : sections.header) !== null && _a !== void 0 ? _a : {},
payload: (_b = sections === null || sections === void 0 ? void 0 : sections.payload) !== null && _b !== void 0 ? _b : sections,
signature: (_c = sections === null || sections === void 0 ? void 0 : sections.signature) !== null && _c !== void 0 ? _c : "",
input: (_d = sections === null || sections === void 0 ? void 0 : sections.input) !== null && _d !== void 0 ? _d : "",
};
}
authenticate(req) {
return __awaiter(this, void 0, void 0, function* () {
/**
* If this is not defined here and is defined as a class method instead
* all the calls to this. or super.error/fail/success fail with error i.e.
* TypeError: (intermediate value).success is not a function
* This is because of some really weird prototype inheritance error. Even if
* this was defined correctly as class method without arrow syntax.
*/
const doneAuth = (error, user, info, status) => {
if (error) {
return this.error(error);
}
if (!user) {
if (status && Array.isArray(status)) {
return this.fail({ info, status }, 401);
}
return this.fail(info, status !== null && status !== void 0 ? status : 401);
}
return this.success(user, info);
};
// Actual implementation
try {
const token = this.extractToken(req);
if (!token) {
throw new Error("Auth token not found from request");
}
const sections = yield this.verifyJwt(token);
this.afterVerifiedCb(this.createSections(sections), doneAuth, req);
}
catch (error) {
if (error instanceof fast_jwt_1.default.TokenError) {
/**
* Without this passport strips away everything
* except the code from TokenError. I guess it has
* something to do with Fast-JWT TokenError
* implementation
*
* Do note that after the this.error call
* the error is no longer an instance of
* TokenError or Error, but just a simple object
*/
const message = error.message;
const code = error.code;
const name = error.name;
const stack = error.stack;
this.error({ message, code, name, stack });
}
else {
this.error(error);
}
}
});
}
}
exports.JwtStrategy = JwtStrategy;