From 9c2ac56eca965233571f71f6785c0df06855d2d8 Mon Sep 17 00:00:00 2001 From: Chuck MANCHUCK Reeves Date: Mon, 21 Aug 2023 15:13:40 +0000 Subject: [PATCH] feat: added verifySignature to jwt package --- packages/jwt/__tests__/jwt.test.ts | 50 ++++++++++++++++++++++++------ packages/jwt/lib/index.ts | 4 +++ packages/jwt/lib/jwt.ts | 17 ++++++++-- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/packages/jwt/__tests__/jwt.test.ts b/packages/jwt/__tests__/jwt.test.ts index e9512432..dbf71615 100644 --- a/packages/jwt/__tests__/jwt.test.ts +++ b/packages/jwt/__tests__/jwt.test.ts @@ -1,5 +1,5 @@ -import { tokenGenerate } from '../lib'; -import { verify } from 'jsonwebtoken'; +import { tokenGenerate, verifySignature } from '../lib'; +import { verify, sign } from 'jsonwebtoken'; import { readFileSync } from 'fs'; import { MissingApplicationIdError, @@ -32,21 +32,19 @@ const acl = { describe('Token Generator', () => { test('Will throw when missing applicationId', () => { // eslint-disable-next-line - // @ts-ignore + // @ts-ignore expect(() => tokenGenerate()).toThrow(new MissingApplicationIdError()); }); test('Will throw when missing privateKey', () => { // eslint-disable-next-line - // @ts-ignore - expect(() => tokenGenerate('app-id')).toThrow( - new MissingPrivateKeyError(), - ); + // @ts-ignore + expect(() => tokenGenerate('app-id')).toThrow(new MissingPrivateKeyError()); }); test('Will throw when applicationId not a string', () => { // eslint-disable-next-line - // @ts-ignore + // @ts-ignore expect(() => tokenGenerate(12345, privateKey)).toThrow( new InvalidApplicationIdError(), ); @@ -54,7 +52,7 @@ describe('Token Generator', () => { test('Will throw when privateKey not a string or buffer', () => { // eslint-disable-next-line - // @ts-ignore + // @ts-ignore expect(() => tokenGenerate(applicationId, 56789)).toThrow( new InvalidPrivateKeyError(), ); @@ -92,4 +90,38 @@ describe('Token Generator', () => { expect(decoded).not.toHaveProperty('ttl'); expect(decoded.acl).toMatchObject(acl); }); + + test('Can Verify signature', () => { + const token = tokenGenerate(applicationId, privateKey, { + ttl, + subject, + acl, + }); + + // eslint-disable-next-line + expect(verifySignature(token, privateKey)).toEqual(true); + }); + + test('Will not validate with invalid key', () => { + const token = tokenGenerate(applicationId, privateKey, { + ttl, + subject, + acl, + }); + + // eslint-disable-next-line + expect(verifySignature(token, 'fizz-buzz')).toEqual(false); + }); + + test('Will not validate with invalid JWT token', () => { + const token = sign({}, 'fizzBuzz'); + + // eslint-disable-next-line + expect(verifySignature(token, privateKey)).toEqual(false); + }); + + test('Will not validate with non JWT token', () => { + // eslint-disable-next-line + expect(verifySignature('fizz-buzz', privateKey)).toEqual(false); + }); }); diff --git a/packages/jwt/lib/index.ts b/packages/jwt/lib/index.ts index 3a11292f..b63c8119 100644 --- a/packages/jwt/lib/index.ts +++ b/packages/jwt/lib/index.ts @@ -15,3 +15,7 @@ export function tokenGenerate( ) { return instance.tokenGenerate(applicationId, privateKey, opts); } + +export function verifySignature(token: string, privateKey: string | Buffer) { + return instance.verifySignature(token, privateKey); +} diff --git a/packages/jwt/lib/jwt.ts b/packages/jwt/lib/jwt.ts index b42b5ee2..db505d1e 100644 --- a/packages/jwt/lib/jwt.ts +++ b/packages/jwt/lib/jwt.ts @@ -1,5 +1,5 @@ import { JWTInterface, GeneratorOptions, Claims } from './common'; -import { sign } from 'jsonwebtoken'; +import { sign, verify } from 'jsonwebtoken'; import { v4 as uuidv4 } from 'uuid'; import { MissingApplicationIdError, @@ -45,6 +45,19 @@ export class JWT implements JWTInterface { }); } + verifySignature(jwt: string, privateKey: string | Buffer): boolean { + try { + verify(jwt, privateKey, { + algorithms: ['RS256'], + }); + return true; + } catch (error) { + log('Error when verifying token', error); + } + + return false; + } + private validateOptions(opts?: GeneratorOptions): Claims { const now = parseInt((Date.now() / 1000).toString(), 10); @@ -70,7 +83,7 @@ export class JWT implements JWTInterface { for (const property in opts) { // eslint-disable-next-line - if (opts.hasOwnProperty(property)) { + if (opts.hasOwnProperty(property)) { claims[property] = opts[property]; } }