diff --git a/lib/jwt.service.spec.ts b/lib/jwt.service.spec.ts index 09151dac..39b33905 100644 --- a/lib/jwt.service.spec.ts +++ b/lib/jwt.service.spec.ts @@ -303,4 +303,79 @@ describe('JWT Service', () => { ).resolves.toBe(`verified_${testPayload}_by_customPublicKey`); }); }); + + describe('should not use invalid sign options', () => { + let jwtService: JwtService; + let testPayloadStr: string = getRandomString(); + + beforeAll(async () => { + jwtService = await setup({ secretOrKeyProvider: undefined }); + }); + + it('should not "sign" expect errors with a "payload" string and "secret"', () => { + // @ts-expect-no-error + expect(() => jwtService.sign(testPayloadStr, { secret: 'secret' })); + }); + + it('should not "signAsync" expect errors with a "payload" string and "privateKey"', () => { + // @ts-expect-no-error + expect(() => + jwtService.signAsync(testPayloadStr, { privateKey: 'privateKey' }) + ); + }); + }); + + describe('should use invalid sign options', () => { + const signOptions: jwt.SignOptions = { + expiresIn: '1d' + }; + + let jwtService: JwtService; + let testPayloadStr: string = getRandomString(); + let testPayloadObj: object = {}; + + beforeAll(async () => { + jwtService = await setup({ signOptions, secretOrKeyProvider: undefined }); + }); + + it('should "sign" expect errors with a "payload" string with "expiresIn"', () => { + expect(() => + // @ts-expect-error + jwtService.sign(testPayloadStr, { expiresIn: 60 }) + ).toThrowError( + 'Payload as string is not allowed with the following sign options: expiresIn' + ); + }); + + it('should "signAsync" expect errors with a "payload" string with "notBefore"', () => { + expect(() => + // @ts-expect-error + jwtService.signAsync(testPayloadStr, { notBefore: 60 }) + ).toThrowError( + 'Payload as string is not allowed with the following sign options: expiresIn, notBefore' + ); + }); + + it('should not "sign" expect errors with a "payload" object with "notBefore" ', () => { + // @ts-expect-no-error + expect(() => jwtService.sign(testPayloadObj, { notBefore: 60 })); + }); + + it('should not "signAsync" expect errors with a "payload" object with "notBefore" ', () => { + // @ts-expect-no-error + expect(() => jwtService.signAsync(testPayloadObj, { notBefore: 60 })); + }); + + it('should "sign" expect errors using "payload" string with already defined invalid sign options', () => { + expect(() => jwtService.sign(testPayloadStr)).toThrowError( + 'Payload as string is not allowed with the following sign options: expiresIn' + ); + }); + + it('should "signAsync" expect errors using "payload" string with already defined invalid sign options', () => { + expect(() => jwtService.signAsync(testPayloadStr)).toThrowError( + 'Payload as string is not allowed with the following sign options: expiresIn' + ); + }); + }); }); diff --git a/lib/jwt.service.ts b/lib/jwt.service.ts index 80ca2e4c..5d688c7f 100644 --- a/lib/jwt.service.ts +++ b/lib/jwt.service.ts @@ -18,6 +18,11 @@ export class JwtService { private readonly options: JwtModuleOptions = {} ) {} + sign( + payload: string, + options?: Omit + ): string; + sign(payload: Buffer | object, options?: JwtSignOptions): string; sign(payload: string | Buffer | object, options?: JwtSignOptions): string { const signOptions = this.mergeJwtOptions( { ...options }, @@ -30,9 +35,29 @@ export class JwtService { JwtSecretRequestType.SIGN ); + const allowedSignOptKeys = ['secret', 'privateKey']; + const signOptKeys = Object.keys(signOptions); + if ( + typeof payload === 'string' && + signOptKeys.some((k) => !allowedSignOptKeys.includes(k)) + ) { + throw new Error( + 'Payload as string is not allowed with the following sign options: ' + + signOptKeys.join(', ') + ); + } + return jwt.sign(payload, secret, signOptions); } + signAsync( + payload: string, + options?: Omit + ): Promise; + signAsync( + payload: Buffer | object, + options?: JwtSignOptions + ): Promise; signAsync( payload: string | Buffer | object, options?: JwtSignOptions @@ -48,6 +73,18 @@ export class JwtService { JwtSecretRequestType.SIGN ); + const allowedSignOptKeys = ['secret', 'privateKey']; + const signOptKeys = Object.keys(signOptions); + if ( + typeof payload === 'string' && + signOptKeys.some((k) => !allowedSignOptKeys.includes(k)) + ) { + throw new Error( + 'Payload as string is not allowed with the following sign options: ' + + signOptKeys.join(', ') + ); + } + return new Promise((resolve, reject) => jwt.sign(payload, secret, signOptions, (err, encoded) => err ? reject(err) : resolve(encoded)