Skip to content

Commit

Permalink
Merge pull request #336 from wprk/master
Browse files Browse the repository at this point in the history
Allow secret to be passed as an option to sign and verify
  • Loading branch information
kamilmysliwiec authored Jul 9, 2020
2 parents 800b3f1 + 60aecc5 commit 4f67f04
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 21 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,19 +152,19 @@ It works the same as `useClass` with one critical difference - `JwtModule` will

The `JwtService` uses [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) underneath.

#### jwtService.sign(payload: string | Object | Buffer, options?: SignOptions): string
#### jwtService.sign(payload: string | Object | Buffer, options?: JwtSignOptions): string

The sign method is an implementation of jsonwebtoken `.sign()`.
The sign method is an implementation of jsonwebtoken `.sign()`. Differing from jsonwebtoken it also allows an additional `secret` property on `options` to override the secret passed in from the module. It only overrides the `secret`, `publicKey` or `privateKey` though not a `secretOrKeyProvider`.

#### jwtService.signAsync(payload: string | Object | Buffer, options?: SignOptions): Promise\<string\>
#### jwtService.signAsync(payload: string | Object | Buffer, options?: JwtSignOptions): Promise\<string\>

The asynchronous `.sign()` method.

#### jwtService.verify\<T extends object = any>(token: string, options?: VerifyOptions): T
#### jwtService.verify\<T extends object = any>(token: string, options?: JwtVerifyOptions): T

The verify method is an implementation of jsonwebtoken `.verify()`.
The verify method is an implementation of jsonwebtoken `.verify()`. Differing from jsonwebtoken it also allows an additional `secret` property on `options` to override the secret passed in from the module. It only overrides the `secret`, `publicKey` or `privateKey` though not a `secretOrKeyProvider`.

#### jwtService.verifyAsync\<T extends object = any>(token: string, options?: VerifyOptions): Promise\<T\>
#### jwtService.verifyAsync\<T extends object = any>(token: string, options?: JwtVerifyOptions): Promise\<T\>

The asynchronous `.verify()` method.

Expand Down
8 changes: 8 additions & 0 deletions lib/interfaces/jwt-module-options.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@ export interface JwtModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
useFactory?: (...args: any[]) => Promise<JwtModuleOptions> | JwtModuleOptions;
inject?: any[];
}

export interface JwtSignOptions extends jwt.SignOptions {
secret?: string | Buffer;
}

export interface JwtVerifyOptions extends jwt.VerifyOptions {
secret?: string | Buffer;
}
31 changes: 31 additions & 0 deletions lib/jwt.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,35 @@ describe('JWT Service', () => {
.mockImplementation((token, secret, options) => secret);
});
});

describe('should use secret key from options', () => {
let jwtService: JwtService;

beforeAll(async () => {
jwtService = await setup({
...config,
secretOrKeyProvider: undefined
});
});

let secret = 'custom';

it('signing should use secret key from options', async () => {
expect(await jwtService.sign('random', { secret })).toBe(secret);
});

it('signing (async) should use secret key from options', async () => {
expect(jwtService.signAsync('random', { secret })).resolves.toBe(secret);
});

it('verifying should use secret key from options', async () => {
expect(await jwtService.verify('random', { secret })).toBe(secret);
});

it('verifying (async) should use secret key from options', async () => {
expect(jwtService.verifyAsync('random', { secret })).resolves.toBe(
secret
);
});
});
});
30 changes: 15 additions & 15 deletions lib/jwt.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { Inject, Injectable, Logger } from '@nestjs/common';
import * as jwt from 'jsonwebtoken';
import {
JwtModuleOptions,
JwtSecretRequestType
JwtSecretRequestType,
JwtVerifyOptions,
JwtSignOptions
} from './interfaces/jwt-module-options.interface';
import { JWT_MODULE_OPTIONS } from './jwt.constants';

Expand All @@ -14,9 +16,9 @@ export class JwtService {
@Inject(JWT_MODULE_OPTIONS) private readonly options: JwtModuleOptions
) {}

sign(payload: string | Buffer | object, options?: jwt.SignOptions): string {
sign(payload: string | Buffer | object, options?: JwtSignOptions): string {
const signOptions = this.mergeJwtOptions(
options,
{ ...options },
'signOptions'
) as jwt.SignOptions;
const secret = this.getSecretKey(
Expand All @@ -31,10 +33,10 @@ export class JwtService {

signAsync(
payload: string | Buffer | object,
options?: jwt.SignOptions
options?: JwtSignOptions
): Promise<string> {
const signOptions = this.mergeJwtOptions(
options,
{ ...options },
'signOptions'
) as jwt.SignOptions;
const secret = this.getSecretKey(
Expand All @@ -51,11 +53,8 @@ export class JwtService {
);
}

verify<T extends object = any>(
token: string,
options?: jwt.VerifyOptions
): T {
const verifyOptions = this.mergeJwtOptions(options, 'verifyOptions');
verify<T extends object = any>(token: string, options?: JwtVerifyOptions): T {
const verifyOptions = this.mergeJwtOptions({ ...options }, 'verifyOptions');
const secret = this.getSecretKey(
token,
options,
Expand All @@ -68,9 +67,9 @@ export class JwtService {

verifyAsync<T extends object = any>(
token: string,
options?: jwt.VerifyOptions
options?: JwtVerifyOptions
): Promise<T> {
const verifyOptions = this.mergeJwtOptions(options, 'verifyOptions');
const verifyOptions = this.mergeJwtOptions({ ...options }, 'verifyOptions');
const secret = this.getSecretKey(
token,
options,
Expand All @@ -93,9 +92,10 @@ export class JwtService {
}

private mergeJwtOptions(
options: jwt.VerifyOptions | jwt.SignOptions,
options: JwtVerifyOptions | JwtSignOptions,
key: 'verifyOptions' | 'signOptions'
): jwt.VerifyOptions | jwt.SignOptions {
delete options.secret;
return options
? {
...(this.options[key] || {}),
Expand All @@ -106,13 +106,13 @@ export class JwtService {

private getSecretKey(
token: string | object | Buffer,
options: jwt.VerifyOptions | jwt.SignOptions,
options: JwtVerifyOptions | JwtSignOptions,
key: 'publicKey' | 'privateKey',
secretRequestType: JwtSecretRequestType
): string | Buffer | jwt.Secret {
let secret = this.options.secretOrKeyProvider
? this.options.secretOrKeyProvider(secretRequestType, token, options)
: this.options.secret || this.options[key];
: options?.secret || this.options.secret || this.options[key];

if (this.options.secretOrPrivateKey) {
this.logger.warn(
Expand Down

0 comments on commit 4f67f04

Please sign in to comment.