From fb2be17697b2098b0a5c55e5ee224deb358b0f30 Mon Sep 17 00:00:00 2001 From: Ryanwalker277 Date: Tue, 27 Feb 2024 21:50:55 +0530 Subject: [PATCH] Feat: Added JWT verification endpoint --- .env.sample | 4 +++- package.json | 1 + src/api/api.controller.ts | 7 +++++++ src/api/api.service.ts | 20 +++++++++++++++++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/.env.sample b/.env.sample index c262650..6316953 100644 --- a/.env.sample +++ b/.env.sample @@ -43,4 +43,6 @@ SENTRY_DSN= # CORS CORS_ALLOWED_ORIGINS=https://example.com CORS_ALLOWED_HEADERS=Content-Type,Authorization,x-application-id -CORS_ALLOWED_METHODS=GET,PUT,POST,DELETE,PATCH,OPTIONS \ No newline at end of file +CORS_ALLOWED_METHODS=GET,PUT,POST,DELETE,PATCH,OPTIONS + +JWKS_URI= \ No newline at end of file diff --git a/package.json b/package.json index 86ac759..31149d9 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "flagsmith-nodejs": "^2.5.2", "got": "^11.8.2", "helmet": "^7.0.0", + "jwks-rsa": "^3.1.0", "passport": "^0.5.2", "passport-http": "^0.3.0", "passport-jwt": "^4.0.1", diff --git a/src/api/api.controller.ts b/src/api/api.controller.ts index 4773816..840d01b 100644 --- a/src/api/api.controller.ts +++ b/src/api/api.controller.ts @@ -358,4 +358,11 @@ export class ApiController { ): Promise { return await this.apiService.loginWithOtp(user, authHeader); } + + @Get('verify-jwt') + async verifyJwt( + @Headers('authorization') token: string, + ): Promise<{ authenticated: boolean; user?: any }> { + return this.apiService.verifyJwt(token); + } } diff --git a/src/api/api.service.ts b/src/api/api.service.ts index 65f36c6..de986d6 100644 --- a/src/api/api.service.ts +++ b/src/api/api.service.ts @@ -30,7 +30,7 @@ const CryptoJS = require('crypto-js'); // eslint-disable-next-line @typescript-eslint/no-var-requires const AES = require('crypto-js/aes'); import Flagsmith from 'flagsmith-nodejs'; - +const jwksClient = require('jwks-rsa');; CryptoJS.lib.WordArray.words; @Injectable() @@ -44,6 +44,13 @@ export class ApiService { private readonly configResolverService: ConfigResolverService, ) {} + private readonly jwksClient = jwksClient({ + jwksUri: this.configService.get('JWKS_URI'), + cache: true, + cacheMaxEntries: 5, + cacheMaxAge: 86400000, + }); + login(user: any, authHeader: string): Promise { return this.fusionAuthService .login(user, authHeader) @@ -646,4 +653,15 @@ export class ApiService { } return registration; } + + async verifyJwt(token: string): Promise<{ authenticated: boolean; user?: any }> { + try { + const decodedToken = await this.jwksClient.getSigningKey(token); + const signingKey = decodedToken.getPublicKey(); + return { authenticated: true, user: decodedToken.payload }; + } catch (error) { + console.error('JWT Verification Error:', error); + return { authenticated: false }; + } + } }