diff --git a/README.md b/README.md index eef6c4e1..5666eede 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,16 @@ The `JwtModule` takes an `options` object: - `verifyOptions` [read more](https://github.com/auth0/node-jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback) - `secretOrPrivateKey` (DEPRECATED!) [read more](https://github.com/auth0/node-jsonwebtoken#jwtsignpayload-secretorprivatekey-options-callback) +For performance purposes, it is advised to pass instances of `KeyObject` to `secret`, `privateKey` and `publicKey` properties of this `options` object. These `KeyObject` can be generated with `createSecretKey()`, `createPrivateKey()` and `createPublicKey()` from Node.js `crypto` module. For example: + +```typescript +import { createSecretKey } from 'crypto'; + +new JwtService({ + secret: createSecretKey(Buffer.from('the secret key')) +}); +``` + ## Support Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). diff --git a/lib/interfaces/jwt-module-options.interface.ts b/lib/interfaces/jwt-module-options.interface.ts index cea71ebc..6022e4cc 100644 --- a/lib/interfaces/jwt-module-options.interface.ts +++ b/lib/interfaces/jwt-module-options.interface.ts @@ -12,8 +12,8 @@ export enum JwtSecretRequestType { export interface JwtModuleOptions { global?: boolean; signOptions?: jwt.SignOptions; - secret?: string | Buffer; - publicKey?: string | Buffer; + secret?: jwt.Secret; + publicKey?: jwt.Secret; privateKey?: jwt.Secret; /** * @deprecated diff --git a/lib/jwt.service.spec.ts b/lib/jwt.service.spec.ts index 67c6fce0..8b1bdab2 100644 --- a/lib/jwt.service.spec.ts +++ b/lib/jwt.service.spec.ts @@ -1,3 +1,10 @@ +import { + createPrivateKey, + createPublicKey, + createSecretKey, + generateKeyPairSync, + KeyObject +} from 'crypto'; import { Test } from '@nestjs/testing'; import * as jwt from 'jsonwebtoken'; import { @@ -152,6 +159,44 @@ describe('JwtService', () => { }); }); + describe('should allow KeyObject for privateKey and publicKey', () => { + const { privateKey, publicKey } = generateKeyPairSync('rsa', { + modulusLength: 2048, + publicKeyEncoding: { type: 'spki', format: 'pem' }, + privateKeyEncoding: { type: 'pkcs8', format: 'pem' } + }); + const privKeyAsObject: KeyObject = createPrivateKey(privateKey); + const pubKeyAsObject: KeyObject = createPublicKey(publicKey); + const testPayload = { foo: 'bar' }; + + let jwtService: JwtService; + + beforeEach(async () => { + jwtService = await setup({ + privateKey: privKeyAsObject, + publicKey: pubKeyAsObject, + signOptions: { algorithm: 'RS256' } + }); + verifySpy.mockRestore(); + signSpy.mockRestore(); + }); + + it('verifying should work', () => { + const token = jwtService.sign(testPayload); + + expect(jwtService.verify(token)).toHaveProperty('foo', 'bar'); + }); + + it('verifying (async) should work', () => { + const token = jwtService.sign(testPayload); + + expect(jwtService.verifyAsync(token)).resolves.toHaveProperty( + 'foo', + 'bar' + ); + }); + }); + describe('should use config.secretOrPrivateKey but warn about deprecation', () => { let jwtService: JwtService; let consoleWarnSpy: jest.SpyInstance; @@ -226,6 +271,36 @@ describe('JwtService', () => { }); }); + describe('should allow KeyObject for secret', () => { + const secretB64: KeyObject = createSecretKey( + Buffer.from('ThisIsARandomSecret', 'base64') + ); + const testPayload = { foo: 'bar' }; + + let jwtService: JwtService; + + beforeEach(async () => { + jwtService = await setup({ secret: secretB64 }); + verifySpy.mockRestore(); + signSpy.mockRestore(); + }); + + it('verifying should use base64 buffer key', () => { + const token = jwt.sign(testPayload, secretB64); + + expect(jwtService.verify(token)).toHaveProperty('foo', 'bar'); + }); + + it('verifying (async) should use base64 buffer key', async () => { + const token = jwt.sign(testPayload, secretB64); + + await expect(jwtService.verifyAsync(token)).resolves.toHaveProperty( + 'foo', + 'bar' + ); + }); + }); + describe('should use secret key from options', () => { let jwtService: JwtService; const testPayload: string = getRandomString();