Skip to content

Commit

Permalink
<feature>: Allow secret to be passed as an option to sign and verify
Browse files Browse the repository at this point in the history
This allows you to pass the `secret` property in the options of sign, signAsync, verify and verifyAsync. It does not override a secretOrKeyProvider though only the secret passed into the JwtModule.

Resolves #302
  • Loading branch information
wprk committed Jul 1, 2020
1 parent aab064d commit 80d078a
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 15 deletions.
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 80d078a

Please sign in to comment.