diff --git a/src/decorators/user.decorator.ts b/src/decorators/user.decorator.ts index 78255e7..db69de8 100644 --- a/src/decorators/user.decorator.ts +++ b/src/decorators/user.decorator.ts @@ -1,15 +1,29 @@ import * as cookie from 'cookie'; import { IKindeUser } from '../lib/kinde.interface'; import { createParamDecorator, ExecutionContext } from '@nestjs/common'; +import { getEnvSafely } from '../lib/kinde.factory'; +import { KINDE_ACCESS_TOKEN, KINDE_DOMAIN_URL } from '../lib/kinde.constant'; +import axios from 'axios'; export const KindeUser = createParamDecorator( - (data: keyof IKindeUser, ctx: ExecutionContext) => { + async (data: keyof IKindeUser, ctx: ExecutionContext) => { try { const request = ctx.switchToHttp().getRequest(); const cookies = cookie.parse(request.headers.cookie || ''); - if (!cookies['user']) return null; - const user = JSON.parse(cookies['user']) as IKindeUser; - return data ? user?.[data] : user; + const token = cookies[KINDE_ACCESS_TOKEN] ?? null; + const headers = { + Accept: 'application/json', + Authorization: `Bearer ${token}`, + }; + const profile = await axios.get( + `${getEnvSafely(KINDE_DOMAIN_URL)}/oauth2/user_profile`, + { + headers, + }, + ); + if (profile.status === 200) { + return profile.data; + } } catch (error) { throw new Error('Error getting user'); } diff --git a/src/guards/abstract.guard.ts b/src/guards/abstract.guard.ts index 4773f54..a734276 100644 --- a/src/guards/abstract.guard.ts +++ b/src/guards/abstract.guard.ts @@ -2,21 +2,12 @@ import jwt from 'jsonwebtoken'; import JwksClient from 'jwks-rsa'; import { KindePayload } from '../lib/kinde.interface'; import { CanActivate, ExecutionContext } from '@nestjs/common'; +import { getEnvSafely } from '../lib/kinde.factory'; +import { KINDE_DOMAIN_URL } from '../lib/kinde.constant'; type TokenCallback = (err: Error | null, key?: string) => void; -const getEnvSafely = (envKey: string) => { - const envVal = process.env[envKey]; - if (!envVal) throw new Error(`Missing env variable ${envKey}!`); - return envVal; -}; - export abstract class AbstractGuard implements CanActivate { - private readonly AUD: string; - constructor() { - this.AUD = getEnvSafely('KINDE_AUDIENCE'); - } - /** * Determines if the user is authorized to access a route. * @param context - The execution context of the request. @@ -31,7 +22,7 @@ export abstract class AbstractGuard implements CanActivate { */ private getKey(header: jwt.JwtHeader, callback: TokenCallback) { const client = JwksClient({ - jwksUri: `${getEnvSafely('KINDE_DOMAIN_URL')}/.well-known/jwks`, + jwksUri: `${getEnvSafely(KINDE_DOMAIN_URL)}/.well-known/jwks`, }); client.getSigningKey(header.kid, function (err, key) { callback(err, key?.getPublicKey()); @@ -46,7 +37,7 @@ export abstract class AbstractGuard implements CanActivate { protected verifyToken(token?: string): Promise { return new Promise((resolve, reject) => { if (!token) return reject(new Error('No JWT token provided!')); - jwt.verify(token, this.getKey, { audience: this.AUD }, (err, decoded) => { + jwt.verify(token, this.getKey, {}, (err, decoded) => { if (err) reject(err); resolve(decoded as KindePayload); }); diff --git a/src/guards/isAuth.guard.ts b/src/guards/isAuth.guard.ts index 72d063c..a853f61 100644 --- a/src/guards/isAuth.guard.ts +++ b/src/guards/isAuth.guard.ts @@ -7,6 +7,7 @@ import * as cookie from 'cookie'; import { Reflector } from '@nestjs/core'; import { AbstractGuard } from './abstract.guard'; import { KindeIsAuth } from '../decorators/auth.decorator'; +import { KINDE_ACCESS_TOKEN } from '../lib/kinde.constant'; @Injectable() export class IsAuthGuard extends AbstractGuard { @@ -22,7 +23,7 @@ export class IsAuthGuard extends AbstractGuard { } const request = context.switchToHttp().getRequest(); const cookies = cookie.parse(request.headers.cookie || ''); - const decoded = await this.verifyToken(cookies['access_token']); + const decoded = await this.verifyToken(cookies[KINDE_ACCESS_TOKEN]); if (!decoded) { throw new UnauthorizedException(); } diff --git a/src/guards/permissions.guard.ts b/src/guards/permissions.guard.ts index 7ea6815..ef4e447 100644 --- a/src/guards/permissions.guard.ts +++ b/src/guards/permissions.guard.ts @@ -7,6 +7,7 @@ import * as cookie from 'cookie'; import { Reflector } from '@nestjs/core'; import { AbstractGuard } from './abstract.guard'; import { KindePermissions } from '../decorators/permissions.decorator'; +import { KINDE_ACCESS_TOKEN } from '../lib/kinde.constant'; @Injectable() export class PermissionsGuard extends AbstractGuard { @@ -25,7 +26,7 @@ export class PermissionsGuard extends AbstractGuard { } const request = context.switchToHttp().getRequest(); const cookies = cookie.parse(request.headers.cookie || ''); - const decoded = await this.verifyToken(cookies['access_token']); + const decoded = await this.verifyToken(cookies[KINDE_ACCESS_TOKEN]); if (!decoded) { throw new UnauthorizedException(); } diff --git a/src/guards/roles.guard.ts b/src/guards/roles.guard.ts index 64b0c71..3cfc19e 100644 --- a/src/guards/roles.guard.ts +++ b/src/guards/roles.guard.ts @@ -7,6 +7,7 @@ import * as cookie from 'cookie'; import { Reflector } from '@nestjs/core'; import { AbstractGuard } from './abstract.guard'; import { KindeRoles } from '../decorators/roles.decorator'; +import { KINDE_ACCESS_TOKEN } from '../lib/kinde.constant'; @Injectable() export class RolesGuard extends AbstractGuard { @@ -22,7 +23,7 @@ export class RolesGuard extends AbstractGuard { } const request = context.switchToHttp().getRequest(); const cookies = cookie.parse(request.headers.cookie || ''); - const decoded = await this.verifyToken(cookies['access_token']); + const decoded = await this.verifyToken(cookies[KINDE_ACCESS_TOKEN]); if (!decoded) { throw new UnauthorizedException(); } diff --git a/src/lib/kinde.constant.ts b/src/lib/kinde.constant.ts index 8490148..162e864 100644 --- a/src/lib/kinde.constant.ts +++ b/src/lib/kinde.constant.ts @@ -1 +1,3 @@ export const KINDE_MODULE_OPTIONS = 'KINDE_MODULE_OPTIONS'; +export const KINDE_DOMAIN_URL = 'KINDE_DOMAIN_URL'; +export const KINDE_ACCESS_TOKEN = 'access_token'; diff --git a/src/lib/kinde.factory.ts b/src/lib/kinde.factory.ts index 9568218..51f7922 100644 --- a/src/lib/kinde.factory.ts +++ b/src/lib/kinde.factory.ts @@ -5,3 +5,8 @@ import { KINDE_MODULE_OPTIONS } from './kinde.constant'; export function createKindeProvider(options: KindeModuleOptions): Provider[] { return [{ provide: KINDE_MODULE_OPTIONS, useValue: options || {} }]; } +export const getEnvSafely = (envKey: string) => { + const envVal = process.env[envKey]; + if (!envVal) throw new Error(`Missing env variable ${envKey}!`); + return envVal; +}; diff --git a/src/lib/kinde.interface.ts b/src/lib/kinde.interface.ts index 7d4644b..bb46b78 100644 --- a/src/lib/kinde.interface.ts +++ b/src/lib/kinde.interface.ts @@ -77,9 +77,11 @@ export interface HasuraRolesEntity { } export type IKindeUser = { - family_name: string | null; - given_name: string | null; - picture: string | null; - email: string; id: string; + preferred_email: string; + username: string; + provided_id: string; + last_name: string; + first_name: string; + picture: string; };