From 8816e6be106c70625cb9889f58368743b24afe31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 09:13:34 +0200 Subject: [PATCH 01/13] Code reformat (indent code 4 spaces, reorganise import order) --- index.ts | 2 +- src/JwtHandler.spec.ts | 313 +++++++++++++++++----------------- src/JwtHandler.ts | 148 ++++++++-------- src/MissingKeyIdError.spec.ts | 35 ++-- src/MissingKeyIdError.ts | 12 +- src/UnknownKeyIdError.spec.ts | 41 ++--- src/UnknownKeyIdError.ts | 24 +-- 7 files changed, 290 insertions(+), 285 deletions(-) diff --git a/index.ts b/index.ts index 56812ba..c57a5c9 100644 --- a/index.ts +++ b/index.ts @@ -1,4 +1,4 @@ -export {TokenExpiredError, NotBeforeError, JsonWebTokenError } from "jsonwebtoken" +export {TokenExpiredError, NotBeforeError, JsonWebTokenError} from "jsonwebtoken" export {JwtHandler, PubkeyResolver, PrivkeyResolver, PubkeyData, PrivkeyData} from "./src/JwtHandler" export {MissingKeyIdError} from "./src/MissingKeyIdError" export {UnknownKeyIdError} from "./src/UnknownKeyIdError" diff --git a/src/JwtHandler.spec.ts b/src/JwtHandler.spec.ts index b3165e3..189696f 100644 --- a/src/JwtHandler.spec.ts +++ b/src/JwtHandler.spec.ts @@ -1,183 +1,186 @@ import * as chai from "chai" import * as chaiAsPromised from "chai-as-promised" import * as jwt from "jsonwebtoken" -chai.use(chaiAsPromised) -const { expect } = chai - import "mocha" -import { JwtHandler, PrivkeyData, PubkeyData } from "./JwtHandler" -import { MissingKeyIdError } from "./MissingKeyIdError" -import { UnknownKeyIdError } from "./UnknownKeyIdError" +import {JwtHandler, PrivkeyData, PubkeyData} from "./JwtHandler" +import {MissingKeyIdError} from "./MissingKeyIdError" +import {UnknownKeyIdError} from "./UnknownKeyIdError" + +chai.use(chaiAsPromised) +const {expect} = chai const debugNamePrefix = "test" // fixtures const keyId = "abc1234" const tokenBody = { - iat: Math.floor(Date.now() / 1000), - dummy: "dummy", - iss: "issuer1", - aud: "audience1", + iat: Math.floor(Date.now() / 1000), + dummy: "dummy", + iss: "issuer1", + aud: "audience1", } + function pubkeyResolver(pubkeyId: string): PubkeyData { - return (pubkeyId === keyId) ? {cert, alg: "RS256"} : null + return (pubkeyId === keyId) ? {cert, alg: "RS256"} : null } + function privkeyResolver(privkeyId: string): PrivkeyData { - return (privkeyId === keyId) ? {key: privateKey, passphrase: privateKeyPass, alg: "RS256"} : null + return (privkeyId === keyId) ? {key: privateKey, passphrase: privateKeyPass, alg: "RS256"} : null } describe("JwtHandler", () => { - describe("extractKeyId", () => { - const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) - it("should return the correct key id from the given JWT", () => { - const jwtRaw = generateJwt(keyId, tokenBody) - expect(jwtHandler.extractKeyId(jwtRaw)).to.equal(keyId) - }) - - it("should be rejected with MissingKeyIdError if the JWT does not contain a kid property in the header", () => { - const jwtRaw = generateJwt(null, tokenBody) - expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(MissingKeyIdError) - }) - - it("should be rejected with JsonWebTokenError if the JWT header is not JSON", () => { - // tslint:disable-next-line:max-line-length - const jwtRaw = "76576576werwerwterertertert.7868765348765zurtiueziuerziutziuzeriuziuwtzuizi34986349.345765347654376543765735765tzreztwrwueruz" - expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(jwt.JsonWebTokenError) - }) - - it("should be rejected with JsonWebTokenError if the JWT is complete garbage", () => { - // tslint:disable-next-line:max-line-length - const jwtRaw = "!\\76576576w!!--///erwerwterertertertöüóAAŐÚÉÁŰ<<7868765348765>> zurtiueziuerz{ }iutziuzer*****iuziuwtzuizi34986349345765347654376543765735765+++====tzreztwrwueruz" - expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(jwt.JsonWebTokenError) - }) - }) - - describe("verify", () => { - const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) - it("should return the JWT body if passed a valid JWT", (done) => { - const jwtRaw = generateJwt(keyId, tokenBody) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.deep.equal(tokenBody).notify(done) - }) - - it("should return the JWT body if passed a valid JWT and validation options that matches the JWT", (done) => { - const jwtRaw = generateJwt(keyId, tokenBody) - expect( - jwtHandler.verify(jwtRaw, {issuer: tokenBody.iss}) - ).to.eventually.deep.equal(tokenBody).notify(done) - }) - - it("should be rejected with JsonWebTokenError if the validation options do not match", (done) => { - const jwtRaw = generateJwt(keyId, tokenBody) - expect( - jwtHandler.verify(jwtRaw, {issuer: "expected_issuer"}) - ).to.eventually.rejectedWith(jwt.JsonWebTokenError).notify(done) - }) - - it("should be rejected with TokenExpiredError if the JWT is already expired", (done) => { - const tokenBodyExpired = { - iat: Math.floor(Date.now() / 1000), - dummy: "dummy", - exp: Math.floor(Date.now() / 1000) - 5000, - } - const jwtRaw = generateJwt(keyId, tokenBodyExpired) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.rejectedWith(jwt.TokenExpiredError).notify(done) - }) - - it("should be rejected with NotBeforeError if the is not yet valid", (done) => { - const tokenBodyNbf = { - iat: Math.floor(Date.now() / 1000), - dummy: "dummy", - nbf: Math.floor(Date.now() / 1000) + 1000, - } - const jwtRaw = generateJwt(keyId, tokenBodyNbf) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.rejectedWith(jwt.NotBeforeError).notify(done) - }) - - it("should be rejected with JsonWebTokenError if the JWT is empty", (done) => { - expect( - jwtHandler.verify("") - ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) - }) - - it("should be rejected with JsonWebTokenError if the JWT is null", (done) => { - expect( - jwtHandler.verify(null as any) - ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) - }) - - it("should be rejected with JsonWebTokenError if the JWT is undefined", (done) => { - expect( - jwtHandler.verify(undefined as any) - ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) - }) - - it("should be rejected with MissingKeyIdError if the JWT does not contain a kid property in the header", (done) => { - const jwtRaw = generateJwt(null, tokenBody) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.rejectedWith(MissingKeyIdError).notify(done) - }) - - it("should be rejected with UnknownKeyIdError if the key id is unknown", (done) => { - const jwtRaw = generateJwt("unknown-key-id", tokenBody) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.rejectedWith(UnknownKeyIdError).notify(done) - }) - - it("should be throw an Error if no pubkey resolver is specified", (done) => { - const jwtHandlerNoPubkeyResolver = new JwtHandler(debugNamePrefix, null, privkeyResolver) - const jwtRaw = generateJwt(keyId, tokenBody) - expect( - jwtHandlerNoPubkeyResolver.verify(jwtRaw) - ).to.eventually.rejectedWith(Error).notify(done) - }) - }) - - describe("create", () => { - const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) - it("should create a valid JWT if called with a key id that exists", (done) => { - jwtHandler.create(tokenBody, keyId) + describe("extractKeyId", () => { + const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) + it("should return the correct key id from the given JWT", () => { + const jwtRaw = generateJwt(keyId, tokenBody) + expect(jwtHandler.extractKeyId(jwtRaw)).to.equal(keyId) + }) + + it("should be rejected with MissingKeyIdError if the JWT does not contain a kid property in the header", () => { + const jwtRaw = generateJwt(null, tokenBody) + expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(MissingKeyIdError) + }) + + it("should be rejected with JsonWebTokenError if the JWT header is not JSON", () => { + // tslint:disable-next-line:max-line-length + const jwtRaw = "76576576werwerwterertertert.7868765348765zurtiueziuerziutziuzeriuziuwtzuizi34986349.345765347654376543765735765tzreztwrwueruz" + expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(jwt.JsonWebTokenError) + }) + + it("should be rejected with JsonWebTokenError if the JWT is complete garbage", () => { + // tslint:disable-next-line:max-line-length + const jwtRaw = "!\\76576576w!!--///erwerwterertertertöüóAAŐÚÉÁŰ<<7868765348765>> zurtiueziuerz{ }iutziuzer*****iuziuwtzuizi34986349345765347654376543765735765+++====tzreztwrwueruz" + expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(jwt.JsonWebTokenError) + }) + }) + + describe("verify", () => { + const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) + it("should return the JWT body if passed a valid JWT", (done) => { + const jwtRaw = generateJwt(keyId, tokenBody) + expect( + jwtHandler.verify(jwtRaw), + ).to.eventually.deep.equal(tokenBody).notify(done) + }) + + it("should return the JWT body if passed a valid JWT and validation options that matches the JWT", (done) => { + const jwtRaw = generateJwt(keyId, tokenBody) + expect( + jwtHandler.verify(jwtRaw, {issuer: tokenBody.iss}), + ).to.eventually.deep.equal(tokenBody).notify(done) + }) + + it("should be rejected with JsonWebTokenError if the validation options do not match", (done) => { + const jwtRaw = generateJwt(keyId, tokenBody) + expect( + jwtHandler.verify(jwtRaw, {issuer: "expected_issuer"}), + ).to.eventually.rejectedWith(jwt.JsonWebTokenError).notify(done) + }) + + it("should be rejected with TokenExpiredError if the JWT is already expired", (done) => { + const tokenBodyExpired = { + iat: Math.floor(Date.now() / 1000), + dummy: "dummy", + exp: Math.floor(Date.now() / 1000) - 5000, + } + const jwtRaw = generateJwt(keyId, tokenBodyExpired) + expect( + jwtHandler.verify(jwtRaw), + ).to.eventually.rejectedWith(jwt.TokenExpiredError).notify(done) + }) + + it("should be rejected with NotBeforeError if the is not yet valid", (done) => { + const tokenBodyNbf = { + iat: Math.floor(Date.now() / 1000), + dummy: "dummy", + nbf: Math.floor(Date.now() / 1000) + 1000, + } + const jwtRaw = generateJwt(keyId, tokenBodyNbf) + expect( + jwtHandler.verify(jwtRaw), + ).to.eventually.rejectedWith(jwt.NotBeforeError).notify(done) + }) + + it("should be rejected with JsonWebTokenError if the JWT is empty", (done) => { + expect( + jwtHandler.verify(""), + ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) + }) + + it("should be rejected with JsonWebTokenError if the JWT is null", (done) => { + expect( + jwtHandler.verify(null as any), + ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) + }) + + it("should be rejected with JsonWebTokenError if the JWT is undefined", (done) => { + expect( + jwtHandler.verify(undefined as any), + ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) + }) + + it("should be rejected with MissingKeyIdError if the JWT does not contain a kid property in the header", (done) => { + const jwtRaw = generateJwt(null, tokenBody) + expect( + jwtHandler.verify(jwtRaw), + ).to.eventually.rejectedWith(MissingKeyIdError).notify(done) + }) + + it("should be rejected with UnknownKeyIdError if the key id is unknown", (done) => { + const jwtRaw = generateJwt("unknown-key-id", tokenBody) + expect( + jwtHandler.verify(jwtRaw), + ).to.eventually.rejectedWith(UnknownKeyIdError).notify(done) + }) + + it("should be throw an Error if no pubkey resolver is specified", (done) => { + const jwtHandlerNoPubkeyResolver = new JwtHandler(debugNamePrefix, null, privkeyResolver) + const jwtRaw = generateJwt(keyId, tokenBody) + expect( + jwtHandlerNoPubkeyResolver.verify(jwtRaw), + ).to.eventually.rejectedWith(Error).notify(done) + }) + }) + + describe("create", () => { + const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) + it("should create a valid JWT if called with a key id that exists", (done) => { + jwtHandler.create(tokenBody, keyId) .then((result) => { - expect( - result.match(/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/) - ).to.be.instanceof(Array) - done() + expect( + result.match(/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/), + ).to.be.instanceof(Array) + done() }) + }) + it("should be rejected with UnknownKeyIdError with a key id that does not exist", (done) => { + const keyIdUnknown = "unknown-key-id" + expect( + jwtHandler.create(tokenBody, keyIdUnknown), + ).to.be.rejectedWith(UnknownKeyIdError).notify(done) + }) + it("should be rejected with Error if no privkey resolver is specified", (done) => { + const jwtHandlerNoPrivkeyResolver = new JwtHandler(debugNamePrefix, pubkeyResolver, null) + expect( + jwtHandlerNoPrivkeyResolver.create(tokenBody, keyId), + ).to.be.rejectedWith(Error).notify(done) + }) + // it("should be rejected with UnknownKeyIdError with a null key id", (done) => { + // expect( + // jwtHandler.create(tokenBody, null) + // ).to.be.rejectedWith(UnknownKeyIdError).notify(done) + // }) }) - it("should be rejected with UnknownKeyIdError with a key id that does not exist", (done) => { - const keyIdUnknown = "unknown-key-id" - expect( - jwtHandler.create(tokenBody, keyIdUnknown) - ).to.be.rejectedWith(UnknownKeyIdError).notify(done) - }) - it("should be rejected with Error if no privkey resolver is specified", (done) => { - const jwtHandlerNoPrivkeyResolver = new JwtHandler(debugNamePrefix, pubkeyResolver, null) - expect( - jwtHandlerNoPrivkeyResolver.create(tokenBody, keyId) - ).to.be.rejectedWith(Error).notify(done) - }) - // it("should be rejected with UnknownKeyIdError with a null key id", (done) => { - // expect( - // jwtHandler.create(tokenBody, null) - // ).to.be.rejectedWith(UnknownKeyIdError).notify(done) - // }) - }) }) function generateJwt(kid: string | null, body: object) { - const header = kid ? {kid} : undefined - return jwt.sign(body, { - key: privateKey, passphrase: privateKeyPass}, {algorithm: "RS256", header} - ) + const header = kid ? {kid} : undefined + return jwt.sign(body, { + key: privateKey, passphrase: privateKeyPass, + }, {algorithm: "RS256", header}, + ) } const cert = ` diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index 340c87e..37f36a9 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -5,8 +5,8 @@ import * as jwt from "jsonwebtoken" import * as util from "util" import {shim} from "util.promisify" -import { MissingKeyIdError } from "./MissingKeyIdError" -import { UnknownKeyIdError } from "./UnknownKeyIdError" +import {MissingKeyIdError} from "./MissingKeyIdError" +import {UnknownKeyIdError} from "./UnknownKeyIdError" export type PubkeyData = { cert: string, alg: string } | undefined | null export type PrivkeyData = { key: string, passphrase: string, alg: string } | undefined | null @@ -21,86 +21,86 @@ shim() // util.promisify shim export class JwtHandler { - private debug: debug.IDebugger + private debug: debug.IDebugger - private pubkeyResolver: PubkeyResolver | null - private privkeyResolver: PrivkeyResolver | null + private pubkeyResolver: PubkeyResolver | null + private privkeyResolver: PrivkeyResolver | null - private jwtVerifyAsync = util.promisify(jwt.verify) as JwtVerifyAsync - private jwtSignAsync = util.promisify(jwt.sign) as JwtSignAsync + private jwtVerifyAsync = util.promisify(jwt.verify) as JwtVerifyAsync + private jwtSignAsync = util.promisify(jwt.sign) as JwtSignAsync - public constructor(debugNamePrefix: string, - pubkeyResolver: PubkeyResolver | null, - privkeyResolver: PrivkeyResolver | null) { - this.debug = debug(debugNamePrefix + ":jwt.handler") - this.pubkeyResolver = pubkeyResolver - this.privkeyResolver = privkeyResolver - } - - /** - * Extract key ID from the given JWT - * - * @param {type} jwtRaw The JWT in raw form, i.e. Base64 coded parts separated with dots - * @return {Promise} Promise to the key id - */ - public extractKeyId(jwtRaw: string): string { - try { - const jwtHeaderBase64 = jwtRaw.split(".", 1) - const jwtHeader = JSON.parse(base64url.decode(jwtHeaderBase64[0])) - if (jwtHeader.kid) { - return jwtHeader.kid - } - throw new MissingKeyIdError() - } catch (err) { - if (!(err instanceof MissingKeyIdError)) { - throw new jwt.JsonWebTokenError("JWT header parsing error", err) - } - throw err + public constructor(debugNamePrefix: string, + pubkeyResolver: PubkeyResolver | null, + privkeyResolver: PrivkeyResolver | null) { + this.debug = debug(debugNamePrefix + ":jwt.handler") + this.pubkeyResolver = pubkeyResolver + this.privkeyResolver = privkeyResolver } - } - /** - * Validates the given JWT - * - * @param {string} jwtRaw The JWT in raw form, i.e. Base64 coded parts separated with dots - * @param {Object} options Validation options (jsonwebtoken module options) - * @return {Promise} Promise to the JWT body - */ - public async verify(jwtRaw: string, options?: jwt.VerifyOptions): Promise { - if (!jwtRaw) { - throw new jwt.JsonWebTokenError("Empty JWT") + /** + * Extract key ID from the given JWT + * + * @param {type} jwtRaw The JWT in raw form, i.e. Base64 coded parts separated with dots + * @return {Promise} Promise to the key id + */ + public extractKeyId(jwtRaw: string): string { + try { + const jwtHeaderBase64 = jwtRaw.split(".", 1) + const jwtHeader = JSON.parse(base64url.decode(jwtHeaderBase64[0])) + if (jwtHeader.kid) { + return jwtHeader.kid + } + throw new MissingKeyIdError() + } catch (err) { + if (!(err instanceof MissingKeyIdError)) { + throw new jwt.JsonWebTokenError("JWT header parsing error", err) + } + throw err + } } - const keyId = await this.extractKeyId(jwtRaw) - debug("verify, key id: " + keyId) - if (this.pubkeyResolver) { - const certData = await this.pubkeyResolver(keyId) - if (!certData) { - throw new UnknownKeyIdError(keyId) - } - debug("cert found") - return this.jwtVerifyAsync(jwtRaw, certData.cert, options) + + /** + * Validates the given JWT + * + * @param {string} jwtRaw The JWT in raw form, i.e. Base64 coded parts separated with dots + * @param {Object} options Validation options (jsonwebtoken module options) + * @return {Promise} Promise to the JWT body + */ + public async verify(jwtRaw: string, options?: jwt.VerifyOptions): Promise { + if (!jwtRaw) { + throw new jwt.JsonWebTokenError("Empty JWT") + } + const keyId = await this.extractKeyId(jwtRaw) + debug("verify, key id: " + keyId) + if (this.pubkeyResolver) { + const certData = await this.pubkeyResolver(keyId) + if (!certData) { + throw new UnknownKeyIdError(keyId) + } + debug("cert found") + return this.jwtVerifyAsync(jwtRaw, certData.cert, options) + } + throw new Error("No public key resolver specified") } - throw new Error("No public key resolver specified") - } - /** - * Creates a new JWT with the given body and signs it with the given key - * - * @param {string} tokenBody The body of the JWT token - * @param {string} keyId The ID of the signing key - * @return {Promise} Promise to the JWT body - */ - public async create(tokenBody: object, keyId: string): Promise { - debug("create, key id: " + keyId) - if (this.privkeyResolver) { - const signingKey = await this.privkeyResolver(keyId) - if (!signingKey) { - throw new UnknownKeyIdError("Unknown key id") - } - debug("priv key found") - return this.jwtSignAsync(tokenBody, signingKey, { algorithm: signingKey.alg, header: { kid: keyId } }) + /** + * Creates a new JWT with the given body and signs it with the given key + * + * @param {string} tokenBody The body of the JWT token + * @param {string} keyId The ID of the signing key + * @return {Promise} Promise to the JWT body + */ + public async create(tokenBody: object, keyId: string): Promise { + debug("create, key id: " + keyId) + if (this.privkeyResolver) { + const signingKey = await this.privkeyResolver(keyId) + if (!signingKey) { + throw new UnknownKeyIdError("Unknown key id") + } + debug("priv key found") + return this.jwtSignAsync(tokenBody, signingKey, {algorithm: signingKey.alg, header: {kid: keyId}}) + } + throw new Error("No private key resolver specified") } - throw new Error("No private key resolver specified") - } } diff --git a/src/MissingKeyIdError.spec.ts b/src/MissingKeyIdError.spec.ts index 0ef8946..74a6498 100644 --- a/src/MissingKeyIdError.spec.ts +++ b/src/MissingKeyIdError.spec.ts @@ -1,27 +1,28 @@ import * as chai from "chai" import * as jwt from "jsonwebtoken" -const { expect } = chai import "mocha" -import { MissingKeyIdError } from "./MissingKeyIdError" +import {MissingKeyIdError} from "./MissingKeyIdError" + +const {expect} = chai function throwMissingKeyIdError() { - throw new MissingKeyIdError() + throw new MissingKeyIdError() } describe("MissingKeyIdError", () => { - it("a new instance should have the appropriate properties", () => { - try { - throwMissingKeyIdError() - } catch (err) { - expect(err.name).to.equal("MissingKeyIdError") - expect(err instanceof jwt.JsonWebTokenError).to.equal(true) - expect(err instanceof Error).to.equal(true) - expect(err.stack).to.not.equal(null) - expect(err.stack).to.not.equal(undefined) - expect(err.toString()).to.equal(`MissingKeyIdError: missing key id`) - expect(err.stack.split("\n")[0]).to.equal(`MissingKeyIdError: missing key id`) - expect(err.stack.split("\n")[1].indexOf("throwMissingKeyIdError")).to.equal(7) - } - }) + it("a new instance should have the appropriate properties", () => { + try { + throwMissingKeyIdError() + } catch (err) { + expect(err.name).to.equal("MissingKeyIdError") + expect(err instanceof jwt.JsonWebTokenError).to.equal(true) + expect(err instanceof Error).to.equal(true) + expect(err.stack).to.not.equal(null) + expect(err.stack).to.not.equal(undefined) + expect(err.toString()).to.equal(`MissingKeyIdError: missing key id`) + expect(err.stack.split("\n")[0]).to.equal(`MissingKeyIdError: missing key id`) + expect(err.stack.split("\n")[1].indexOf("throwMissingKeyIdError")).to.equal(7) + } + }) }) diff --git a/src/MissingKeyIdError.ts b/src/MissingKeyIdError.ts index 6ee6b35..3e44f07 100644 --- a/src/MissingKeyIdError.ts +++ b/src/MissingKeyIdError.ts @@ -1,12 +1,12 @@ -import { JsonWebTokenError } from "jsonwebtoken" +import {JsonWebTokenError} from "jsonwebtoken" /** * Error subclass for signaling that the kid field is not present in the JWT header */ export class MissingKeyIdError extends JsonWebTokenError { - constructor() { - super("missing key id") - this.name = this.constructor.name - Error.captureStackTrace(this, this.constructor) - } + constructor() { + super("missing key id") + this.name = this.constructor.name + Error.captureStackTrace(this, this.constructor) + } } diff --git a/src/UnknownKeyIdError.spec.ts b/src/UnknownKeyIdError.spec.ts index e6427c9..151d5f1 100644 --- a/src/UnknownKeyIdError.spec.ts +++ b/src/UnknownKeyIdError.spec.ts @@ -1,32 +1,33 @@ import * as chai from "chai" import * as jwt from "jsonwebtoken" -const { expect } = chai import "mocha" -import { UnknownKeyIdError } from "./UnknownKeyIdError" +import {UnknownKeyIdError} from "./UnknownKeyIdError" + +const {expect} = chai const keyId = "keyid_1" function throwUnknownKeyIdError() { - throw new UnknownKeyIdError(keyId) + throw new UnknownKeyIdError(keyId) } describe("UnknownKeyIdError", () => { - it("a new instance should have the appropriate properties", () => { - try { - throwUnknownKeyIdError() - } catch (err) { - expect(err.name).to.equal("UnknownKeyIdError") - expect(err instanceof UnknownKeyIdError).to.equal(true) - expect(err instanceof jwt.JsonWebTokenError).to.equal(true) - expect(err instanceof Error).to.equal(true) - expect(err.stack).to.not.equal(null) - expect(err.stack).to.not.equal(undefined) - expect(err.toString()).to.equal(`UnknownKeyIdError: unknown key id: ${keyId}`) - expect(err.keyId).to.equal(keyId) - expect(err.message).to.equal(`unknown key id: ${keyId}`) - expect(err.stack.split("\n")[0]).to.equal(`UnknownKeyIdError: unknown key id: ${keyId}`) - expect(err.stack.split("\n")[1].indexOf("throwUnknownKeyIdError")).to.equal(7) - } - }) + it("a new instance should have the appropriate properties", () => { + try { + throwUnknownKeyIdError() + } catch (err) { + expect(err.name).to.equal("UnknownKeyIdError") + expect(err instanceof UnknownKeyIdError).to.equal(true) + expect(err instanceof jwt.JsonWebTokenError).to.equal(true) + expect(err instanceof Error).to.equal(true) + expect(err.stack).to.not.equal(null) + expect(err.stack).to.not.equal(undefined) + expect(err.toString()).to.equal(`UnknownKeyIdError: unknown key id: ${keyId}`) + expect(err.keyId).to.equal(keyId) + expect(err.message).to.equal(`unknown key id: ${keyId}`) + expect(err.stack.split("\n")[0]).to.equal(`UnknownKeyIdError: unknown key id: ${keyId}`) + expect(err.stack.split("\n")[1].indexOf("throwUnknownKeyIdError")).to.equal(7) + } + }) }) diff --git a/src/UnknownKeyIdError.ts b/src/UnknownKeyIdError.ts index 70fcedf..f5f147e 100644 --- a/src/UnknownKeyIdError.ts +++ b/src/UnknownKeyIdError.ts @@ -1,20 +1,20 @@ -import { JsonWebTokenError } from "jsonwebtoken" +import {JsonWebTokenError} from "jsonwebtoken" /** * Error subclass for signaling that the given key id is not known */ export class UnknownKeyIdError extends JsonWebTokenError { - public keyId: string + public keyId: string - /** - * Creates a new instance with the specified key id - * @param {string} keyId The key id - */ - constructor(keyId: string) { - super("unknown key id: " + keyId) - this.name = this.constructor.name - Error.captureStackTrace(this, this.constructor) - this.keyId = keyId - } + /** + * Creates a new instance with the specified key id + * @param {string} keyId The key id + */ + constructor(keyId: string) { + super("unknown key id: " + keyId) + this.name = this.constructor.name + Error.captureStackTrace(this, this.constructor) + this.keyId = keyId + } } From a0e48153c88c3583fb028b7509e57e1024d12b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 09:14:33 +0200 Subject: [PATCH 02/13] Remove unused bluebird import --- types/index.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index e9d89da..e55fff7 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,4 +1,3 @@ -import * as Promise from "bluebird" import {JsonWebTokenError, VerifyOptions} from "jsonwebtoken" export {TokenExpiredError, NotBeforeError, JsonWebTokenError} from "jsonwebtoken" From d69a290a1c979ea8346ae5051e2fc93aeb2d0349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 09:17:08 +0200 Subject: [PATCH 03/13] Remove unnecessary TS type (definitions are autogenerated by TS inside dist folder) --- types/index.d.ts | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 types/index.d.ts diff --git a/types/index.d.ts b/types/index.d.ts deleted file mode 100644 index e55fff7..0000000 --- a/types/index.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {JsonWebTokenError, VerifyOptions} from "jsonwebtoken" - -export {TokenExpiredError, NotBeforeError, JsonWebTokenError} from "jsonwebtoken" - -type PublicKeyResolver = (keyId: string) => { cert: string, alg: string } | Promise<{ cert: string, alg: string }>; -type PrivateKeyResolver = (keyId: string) => { key: string, passphrase: string, alg: string } | Promise<{ key: string, passphrase: string, alg: string }>; - -export class MissingKeyIdError extends JsonWebTokenError { - constructor() -} - -export class UnknownKeyIdError extends JsonWebTokenError { - constructor(keyId: string) -} - -export interface HandlerObject { - extractKeyId(jwtRaw: string): Promise; - - verify(jwtRaw: string, options: VerifyOptions): Promise; - - create(tokenBody: string | Buffer | object, keyId: string): Promise; -} - -export function Handler(debugNamePrefix: string, publicKeyResolver?: PublicKeyResolver, privateKeyResolver?: PrivateKeyResolver): HandlerObject; From 8ed95a22869aa34a648dfce424d7ba211fbfde64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 09:26:41 +0200 Subject: [PATCH 04/13] Use more specific type constraints for stronger type checks --- src/JwtHandler.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index 37f36a9..6ad535f 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -14,8 +14,8 @@ export type PrivkeyData = { key: string, passphrase: string, alg: string } | und export type PubkeyResolver = (keyId: string) => PubkeyData | Promise export type PrivkeyResolver = (keyId: string) => PrivkeyData | Promise -type JwtVerifyAsync = (token: string, publicKey: string, options?: jwt.VerifyOptions) => Promise -type JwtSignAsync = (payload: object, privateKey: {}, options?: jwt.SignOptions) => Promise +type JwtVerifyAsync = (token: string, publicKey: string | Buffer, options?: jwt.VerifyOptions) => Promise +type JwtSignAsync = (payload: string | Buffer | object, privateKey: {}, options?: jwt.SignOptions) => Promise shim() // util.promisify shim @@ -66,7 +66,7 @@ export class JwtHandler { * @param {Object} options Validation options (jsonwebtoken module options) * @return {Promise} Promise to the JWT body */ - public async verify(jwtRaw: string, options?: jwt.VerifyOptions): Promise { + public async verify(jwtRaw: string, options?: jwt.VerifyOptions): Promise { if (!jwtRaw) { throw new jwt.JsonWebTokenError("Empty JWT") } @@ -90,7 +90,7 @@ export class JwtHandler { * @param {string} keyId The ID of the signing key * @return {Promise} Promise to the JWT body */ - public async create(tokenBody: object, keyId: string): Promise { + public async create(tokenBody: string | Buffer | { [key: string]: any }, keyId: string): Promise { debug("create, key id: " + keyId) if (this.privkeyResolver) { const signingKey = await this.privkeyResolver(keyId) From 1ed1990bec944055dcf01c7f93d50355cda83b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 09:28:56 +0200 Subject: [PATCH 05/13] Some code refactor (throw error at end of extractKeyId method instead in try-catch block) --- src/JwtHandler.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index 6ad535f..82e3547 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -50,13 +50,11 @@ export class JwtHandler { if (jwtHeader.kid) { return jwtHeader.kid } - throw new MissingKeyIdError() } catch (err) { - if (!(err instanceof MissingKeyIdError)) { - throw new jwt.JsonWebTokenError("JWT header parsing error", err) - } - throw err + throw new jwt.JsonWebTokenError("JWT header parsing error", err) } + + throw new MissingKeyIdError() } /** From 353afcbf438fafbf97387a45d2ac02508fc6856f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 09:39:31 +0200 Subject: [PATCH 06/13] Fixed tslint errors --- src/JwtHandler.spec.ts | 31 ++++++++++++++++--------------- src/JwtHandler.ts | 1 + 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/JwtHandler.spec.ts b/src/JwtHandler.spec.ts index 189696f..1f00975 100644 --- a/src/JwtHandler.spec.ts +++ b/src/JwtHandler.spec.ts @@ -61,21 +61,21 @@ describe("JwtHandler", () => { it("should return the JWT body if passed a valid JWT", (done) => { const jwtRaw = generateJwt(keyId, tokenBody) expect( - jwtHandler.verify(jwtRaw), + jwtHandler.verify(jwtRaw) ).to.eventually.deep.equal(tokenBody).notify(done) }) it("should return the JWT body if passed a valid JWT and validation options that matches the JWT", (done) => { const jwtRaw = generateJwt(keyId, tokenBody) expect( - jwtHandler.verify(jwtRaw, {issuer: tokenBody.iss}), + jwtHandler.verify(jwtRaw, {issuer: tokenBody.iss}) ).to.eventually.deep.equal(tokenBody).notify(done) }) it("should be rejected with JsonWebTokenError if the validation options do not match", (done) => { const jwtRaw = generateJwt(keyId, tokenBody) expect( - jwtHandler.verify(jwtRaw, {issuer: "expected_issuer"}), + jwtHandler.verify(jwtRaw, {issuer: "expected_issuer"}) ).to.eventually.rejectedWith(jwt.JsonWebTokenError).notify(done) }) @@ -87,7 +87,7 @@ describe("JwtHandler", () => { } const jwtRaw = generateJwt(keyId, tokenBodyExpired) expect( - jwtHandler.verify(jwtRaw), + jwtHandler.verify(jwtRaw) ).to.eventually.rejectedWith(jwt.TokenExpiredError).notify(done) }) @@ -99,39 +99,40 @@ describe("JwtHandler", () => { } const jwtRaw = generateJwt(keyId, tokenBodyNbf) expect( - jwtHandler.verify(jwtRaw), + jwtHandler.verify(jwtRaw) ).to.eventually.rejectedWith(jwt.NotBeforeError).notify(done) }) it("should be rejected with JsonWebTokenError if the JWT is empty", (done) => { expect( - jwtHandler.verify(""), + jwtHandler.verify("") ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) }) it("should be rejected with JsonWebTokenError if the JWT is null", (done) => { expect( - jwtHandler.verify(null as any), + jwtHandler.verify(null as any) ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) }) it("should be rejected with JsonWebTokenError if the JWT is undefined", (done) => { expect( - jwtHandler.verify(undefined as any), + jwtHandler.verify(undefined as any) ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) }) + // tslint:disable-next-line:max-line-length it("should be rejected with MissingKeyIdError if the JWT does not contain a kid property in the header", (done) => { const jwtRaw = generateJwt(null, tokenBody) expect( - jwtHandler.verify(jwtRaw), + jwtHandler.verify(jwtRaw) ).to.eventually.rejectedWith(MissingKeyIdError).notify(done) }) it("should be rejected with UnknownKeyIdError if the key id is unknown", (done) => { const jwtRaw = generateJwt("unknown-key-id", tokenBody) expect( - jwtHandler.verify(jwtRaw), + jwtHandler.verify(jwtRaw) ).to.eventually.rejectedWith(UnknownKeyIdError).notify(done) }) @@ -139,7 +140,7 @@ describe("JwtHandler", () => { const jwtHandlerNoPubkeyResolver = new JwtHandler(debugNamePrefix, null, privkeyResolver) const jwtRaw = generateJwt(keyId, tokenBody) expect( - jwtHandlerNoPubkeyResolver.verify(jwtRaw), + jwtHandlerNoPubkeyResolver.verify(jwtRaw) ).to.eventually.rejectedWith(Error).notify(done) }) }) @@ -150,7 +151,7 @@ describe("JwtHandler", () => { jwtHandler.create(tokenBody, keyId) .then((result) => { expect( - result.match(/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/), + result.match(/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/) ).to.be.instanceof(Array) done() }) @@ -158,13 +159,13 @@ describe("JwtHandler", () => { it("should be rejected with UnknownKeyIdError with a key id that does not exist", (done) => { const keyIdUnknown = "unknown-key-id" expect( - jwtHandler.create(tokenBody, keyIdUnknown), + jwtHandler.create(tokenBody, keyIdUnknown) ).to.be.rejectedWith(UnknownKeyIdError).notify(done) }) it("should be rejected with Error if no privkey resolver is specified", (done) => { const jwtHandlerNoPrivkeyResolver = new JwtHandler(debugNamePrefix, pubkeyResolver, null) expect( - jwtHandlerNoPrivkeyResolver.create(tokenBody, keyId), + jwtHandlerNoPrivkeyResolver.create(tokenBody, keyId) ).to.be.rejectedWith(Error).notify(done) }) // it("should be rejected with UnknownKeyIdError with a null key id", (done) => { @@ -179,7 +180,7 @@ function generateJwt(kid: string | null, body: object) { const header = kid ? {kid} : undefined return jwt.sign(body, { key: privateKey, passphrase: privateKeyPass, - }, {algorithm: "RS256", header}, + }, {algorithm: "RS256", header} ) } diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index 82e3547..b009a67 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -14,6 +14,7 @@ export type PrivkeyData = { key: string, passphrase: string, alg: string } | und export type PubkeyResolver = (keyId: string) => PubkeyData | Promise export type PrivkeyResolver = (keyId: string) => PrivkeyData | Promise +// tslint:disable-next-line:max-line-length type JwtVerifyAsync = (token: string, publicKey: string | Buffer, options?: jwt.VerifyOptions) => Promise type JwtSignAsync = (payload: string | Buffer | object, privateKey: {}, options?: jwt.SignOptions) => Promise From b7607e77c4e0a8c4150ff6bd8127c98f723098ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 09:47:11 +0200 Subject: [PATCH 07/13] Make verify method generic --- src/JwtHandler.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index b009a67..b24010d 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -15,7 +15,7 @@ export type PubkeyResolver = (keyId: string) => PubkeyData | Promise export type PrivkeyResolver = (keyId: string) => PrivkeyData | Promise // tslint:disable-next-line:max-line-length -type JwtVerifyAsync = (token: string, publicKey: string | Buffer, options?: jwt.VerifyOptions) => Promise +type JwtVerifyAsync = (token: string, publicKey: string | Buffer, options?: jwt.VerifyOptions) => Promise type JwtSignAsync = (payload: string | Buffer | object, privateKey: {}, options?: jwt.SignOptions) => Promise shim() // util.promisify shim @@ -65,7 +65,7 @@ export class JwtHandler { * @param {Object} options Validation options (jsonwebtoken module options) * @return {Promise} Promise to the JWT body */ - public async verify(jwtRaw: string, options?: jwt.VerifyOptions): Promise { + public async verify(jwtRaw: string, options?: jwt.VerifyOptions): Promise { if (!jwtRaw) { throw new jwt.JsonWebTokenError("Empty JWT") } @@ -77,7 +77,7 @@ export class JwtHandler { throw new UnknownKeyIdError(keyId) } debug("cert found") - return this.jwtVerifyAsync(jwtRaw, certData.cert, options) + return this.jwtVerifyAsync(jwtRaw, certData.cert, options) } throw new Error("No public key resolver specified") } From 495654a861509797447f3d0532152499dbede6cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 11:01:59 +0200 Subject: [PATCH 08/13] Add ability to pass option object to Handler constructor --- README.md | 8 ++++++++ src/JwtHandler.ts | 27 ++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ea8c53f..9c0ae08 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,14 @@ function privkeyResolver (keyId) { const jwtHandler = new jwt.JwtHandler('myproject', pubkeyResolver, privkeyResolver) +// or with options object + +const jwtHandler = new jwt.JwtHandler({ + debugNamePrefix: 'myproject', + pubkeyResolver: pubkeyResolver, + privkeyResolver: privkeyResolver, +}) + // Verifying JWT tokens jwtHandler.verify(jwtRaw) .then(jwtBody => { diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index b24010d..c7d3f59 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -18,6 +18,12 @@ export type PrivkeyResolver = (keyId: string) => PrivkeyData | Promise(token: string, publicKey: string | Buffer, options?: jwt.VerifyOptions) => Promise type JwtSignAsync = (payload: string | Buffer | object, privateKey: {}, options?: jwt.SignOptions) => Promise +export interface JwtHandlerOptions { + debugNamePrefix: string + pubkeyResolver?: PubkeyResolver + privkeyResolver?: PrivkeyResolver +} + shim() // util.promisify shim export class JwtHandler { @@ -30,12 +36,23 @@ export class JwtHandler { private jwtVerifyAsync = util.promisify(jwt.verify) as JwtVerifyAsync private jwtSignAsync = util.promisify(jwt.sign) as JwtSignAsync + public constructor(options: JwtHandlerOptions) public constructor(debugNamePrefix: string, - pubkeyResolver: PubkeyResolver | null, - privkeyResolver: PrivkeyResolver | null) { - this.debug = debug(debugNamePrefix + ":jwt.handler") - this.pubkeyResolver = pubkeyResolver - this.privkeyResolver = privkeyResolver + pubkeyResolver?: PubkeyResolver | null, + privkeyResolver?: PrivkeyResolver | null) + public constructor(arg1: string | JwtHandlerOptions, arg2?: PubkeyResolver | null, arg3?: PrivkeyResolver | null) { + if (typeof arg1 === "object") { + arg2 = arg1.pubkeyResolver + arg3 = arg1.privkeyResolver + arg1 = arg1.debugNamePrefix + } + + arg2 = arg2 || null + arg3 = arg3 || null + + this.debug = debug(arg1 + ":jwt.handler") + this.pubkeyResolver = arg2 + this.privkeyResolver = arg3 } /** From df06366b119499e5eb47769ae9749e9e048e7d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 11:03:03 +0200 Subject: [PATCH 09/13] Fix tslint error line-max-length --- src/JwtHandler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index c7d3f59..11bc843 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -82,7 +82,8 @@ export class JwtHandler { * @param {Object} options Validation options (jsonwebtoken module options) * @return {Promise} Promise to the JWT body */ - public async verify(jwtRaw: string, options?: jwt.VerifyOptions): Promise { + public async verify(jwtRaw: string, + options?: jwt.VerifyOptions): Promise { if (!jwtRaw) { throw new jwt.JsonWebTokenError("Empty JWT") } From 76c1f221b298da1dff6b021736476e810395e968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Thu, 10 Aug 2017 13:59:26 +0200 Subject: [PATCH 10/13] Add missing changes --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2ad715..1579df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## Next release + +- Add `options` object to `Handler`'s constructor +- Make `verify` method's return value generic + ## 2.0.0 2017.08.09 - Complete reimplementation in TypeScript From 96214d654cc0b1ad93464bf7527927538b12598c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Tue, 15 Aug 2017 15:10:06 +0200 Subject: [PATCH 11/13] Public key's data do not recuire alg property --- src/JwtHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index 11bc843..6686ce0 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -8,7 +8,7 @@ import {shim} from "util.promisify" import {MissingKeyIdError} from "./MissingKeyIdError" import {UnknownKeyIdError} from "./UnknownKeyIdError" -export type PubkeyData = { cert: string, alg: string } | undefined | null +export type PubkeyData = { cert: string } export type PrivkeyData = { key: string, passphrase: string, alg: string } | undefined | null export type PubkeyResolver = (keyId: string) => PubkeyData | Promise From 8a4d51d2e443e0ab9a5a8357b9ae883aedaf0875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Tue, 15 Aug 2017 15:44:52 +0200 Subject: [PATCH 12/13] Add undefined | null types to PubkeyData --- src/JwtHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index 6686ce0..222b6ac 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -8,7 +8,7 @@ import {shim} from "util.promisify" import {MissingKeyIdError} from "./MissingKeyIdError" import {UnknownKeyIdError} from "./UnknownKeyIdError" -export type PubkeyData = { cert: string } +export type PubkeyData = { cert: string } | undefined | null export type PrivkeyData = { key: string, passphrase: string, alg: string } | undefined | null export type PubkeyResolver = (keyId: string) => PubkeyData | Promise From ef21cd0ca571fde1608c8606747904688f3062a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Vince?= Date: Tue, 15 Aug 2017 15:52:47 +0200 Subject: [PATCH 13/13] Add alg as optional property to PubkeyData --- src/JwtHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index 222b6ac..8c9d9bd 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -8,7 +8,7 @@ import {shim} from "util.promisify" import {MissingKeyIdError} from "./MissingKeyIdError" import {UnknownKeyIdError} from "./UnknownKeyIdError" -export type PubkeyData = { cert: string } | undefined | null +export type PubkeyData = { cert: string, alg?: string } | undefined | null export type PrivkeyData = { key: string, passphrase: string, alg: string } | undefined | null export type PubkeyResolver = (keyId: string) => PubkeyData | Promise