diff --git a/src/index.d.ts b/src/index.d.ts index f9dee32..5e78cfb 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -62,9 +62,15 @@ declare class TokenError extends Error { type SignerCallback = (e: Error | TokenError | null, token: string) => void type VerifierCallback = (e: Error | TokenError | null, payload: any) => void +type DecodedJwt = { + header: { [key: string]: any }, + payload: string, + signature: string +} + type KeyFetcher = - | ((header: { [key: string]: any }) => Promise) - | ((header: { [key: string]: any }, cb: (err: Error | TokenError | null, key: string | Buffer) => void) => void) + | ((DecodedJwt: DecodedJwt) => Promise) + | ((DecodedJwt: DecodedJwt, cb: (err: Error | TokenError | null, key: string | Buffer) => void) => void) declare function SignerSync(payload: string | Buffer | { [key: string]: any }): string declare function SignerAsync(payload: string | Buffer | { [key: string]: any }): Promise diff --git a/src/signer.js b/src/signer.js index e0827a2..1ea2a5d 100644 --- a/src/signer.js +++ b/src/signer.js @@ -125,7 +125,7 @@ function sign( } // Get the key asynchronously - getAsyncKey(key, header, (err, currentKey) => { + getAsyncKey(key, { header, payload }, (err, currentKey) => { if (err) { const error = TokenError.wrap(err, TokenError.codes.keyFetchingError, 'Cannot fetch key.') return callback(error) diff --git a/src/utils.js b/src/utils.js index 8fbb844..9e87830 100644 --- a/src/utils.js +++ b/src/utils.js @@ -5,8 +5,8 @@ const algorithmMatcher = /"alg"\s*:\s*"[HERP]S(256|384)"/m const edAlgorithmMatcher = /"alg"\s*:\s*"EdDSA"/m const ed448CurveMatcher = /"crv"\s*:\s*"Ed448"/m -function getAsyncKey(handler, header, callback) { - const result = handler(header, callback) +function getAsyncKey(handler, decoded, callback) { + const result = handler(decoded, callback) if (result && typeof result.then === 'function') { result @@ -31,7 +31,7 @@ function ensurePromiseCallback(callback) { }) return [ - function(err, token) { + function (err, token) { if (err) { return promiseReject(err) } diff --git a/src/verifier.js b/src/verifier.js index 8d22c79..2f801b1 100644 --- a/src/verifier.js +++ b/src/verifier.js @@ -324,7 +324,7 @@ function verify( } // Get the key asynchronously - getAsyncKey(key, header, (err, currentKey) => { + getAsyncKey(key, { header, payload, signature }, (err, currentKey) => { if (err) { return callback( cacheSet(cacheContext, TokenError.wrap(err, TokenError.codes.keyFetchingError, 'Cannot fetch key.')) diff --git a/test/signer.spec.js b/test/signer.spec.js index f376b7d..1213fbc 100644 --- a/test/signer.spec.js +++ b/test/signer.spec.js @@ -44,6 +44,25 @@ function sign(payload, options, callback) { return signer(payload, callback) } +test('it passes the correct decoded jwt token to the key callback', async t => { + sign( + { a: 1 }, + { + noTimestamp: true, + key: decodedJwt => { + t.strictSame(decodedJwt, { + payload: { a: 1 }, + header: { + alg: undefined, + typ: 'JWT', + kid: undefined + } + }) + } + } + ) +}) + test('it correctly returns a token - sync', t => { t.equal( sign({ a: 1 }, { noTimestamp: true }), @@ -79,7 +98,10 @@ test('it correctly returns a token - sync', t => { test('it correctly returns a token - async - key with callback', async t => { t.equal( - await sign({ a: 1 }, { key: (_h, callback) => setTimeout(() => callback(null, 'secret'), 10), noTimestamp: true }), + await sign( + { a: 1 }, + { key: (_decodedJwt, callback) => setTimeout(() => callback(null, 'secret'), 10), noTimestamp: true } + ), 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM' ) }) @@ -513,7 +535,7 @@ test('it correctly handle errors - callback', t => { sign( { a: 1 }, { - key: (header, callback) => { + key: (_decodedJwt, callback) => { callback(new Error('FAILED')) }, noTimestamp: true @@ -531,7 +553,7 @@ test('it correctly validates the key received from the callback', t => { sign( { a: 1 }, { - key: (header, callback) => { + key: (_decodedJwt, callback) => { callback(null, 123) }, noTimestamp: true @@ -552,7 +574,7 @@ test('it correctly handle errors - evented callback', t => { sign( { a: 1 }, { - key: (header, callback) => { + key: (_decodedJwt, callback) => { process.nextTick(() => callback(null, 'FAILED')) }, noTimestamp: true, diff --git a/test/types.spec.ts b/test/types.spec.ts index 10350ea..9de30fc 100644 --- a/test/types.spec.ts +++ b/test/types.spec.ts @@ -3,7 +3,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-empty-function */ -import { createDecoder, createSigner, createVerifier, JwtHeader, TokenError } from '..' +import { createDecoder, createSigner, createVerifier, DecodedJwt, JwtHeader, TokenError } from '..' import { expectAssignable, expectNotAssignable } from 'tsd' // Signing @@ -18,7 +18,7 @@ signerAsync({ key: '1' }, (_e: Error | null, _token?: string) => {}) // Dynamic key in callback style createSigner({ clockTimestamp: 10, - key(_header: { [key: string]: any }, cb: (e: Error | null, key: string) => void): void { + key(_decodedJwt: DecodedJwt, cb: (e: Error | null, key: string) => void): void { cb(null, 'KEY') } })({ key: 1 }).then(console.log, console.log) @@ -26,7 +26,7 @@ createSigner({ // Dynamic key in async style createSigner({ clockTimestamp: 10, - async key(_header: { [key: string]: any }) { + async key(_decodedJwt: DecodedJwt) { return 'KEY' } })({ key: 1 }).then(console.log, console.log) @@ -48,7 +48,7 @@ verifierAsync(Buffer.from('456'), (_e: Error | null, _token?: string) => {}) // Dynamic key in callback style createVerifier({ clockTimestamp: 10, - key(_header: { [key: string]: any }, cb: (e: Error | null, key: string) => void): void { + key(_decodedJwt: DecodedJwt, cb: (e: Error | null, key: string) => void): void { cb(null, 'KEY') } })('123').then(console.log, console.log) @@ -56,7 +56,7 @@ createVerifier({ // Dynamic key in async style createVerifier({ clockTimestamp: 10, - async key(_header: { [key: string]: any }) { + async key(_decodedJwt: DecodedJwt) { return 'KEY' } })('456').then(console.log, console.log) diff --git a/test/verifier.spec.js b/test/verifier.spec.js index 339b819..8bd8c65 100644 --- a/test/verifier.spec.js +++ b/test/verifier.spec.js @@ -41,6 +41,25 @@ function verify(token, options, callback) { return verifier(token, callback) } +test('it gets the correct decoded jwt token as argument on the key callback', async t => { + verify('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM', { + key: async decoded => { + t.strictSame( + decoded, + { + header: { typ: 'JWT', alg: 'HS256' }, + payload: { a: 1 }, + signature: '57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM' + } + ) + + return Buffer.from('secret', 'utf-8') + }, + noTimestamp: true, + complete: true + }) +}) + test('it correctly verifies a token - sync', t => { t.strictSame( verify('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM', { @@ -134,7 +153,7 @@ test('it correctly verifies a token - sync', t => { test('it correctly verifies a token - async - key with callback', async t => { t.strictSame( await verify('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM', { - key: (_h, callback) => setTimeout(() => callback(null, 'secret'), 10), + key: (_decodedJwt, callback) => setTimeout(() => callback(null, 'secret'), 10), noTimestamp: true }), { a: 1 } @@ -143,7 +162,7 @@ test('it correctly verifies a token - async - key with callback', async t => { t.strictSame( await verify('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM', { algorithms: ['HS256'], - key: (_h, callback) => setTimeout(() => callback(null, 'secret'), 10), + key: (_decodedJwt, callback) => setTimeout(() => callback(null, 'secret'), 10), noTimestamp: true, complete: true }), @@ -247,7 +266,7 @@ test('it correctly handle errors - callback', t => { verify( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM', { - key: (header, callback) => { + key: (_decodedJwt, callback) => { callback(new Error('FAILED')) } }, @@ -264,7 +283,7 @@ test('it correctly handle errors - evented callback', t => { verify( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM', { - key: (header, callback) => { + key: (_decodedJwt, callback) => { process.nextTick(() => callback(null, 'FAILED')) } },