Skip to content

Commit

Permalink
feat: get token fron cookie or authorization header
Browse files Browse the repository at this point in the history
  • Loading branch information
AmineYagoub committed Aug 8, 2024
1 parent 30d7335 commit 06ba0ff
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 41 deletions.
12 changes: 8 additions & 4 deletions src/decorators/user.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,23 @@ export const KindeUser = createParamDecorator(
try {
const request = ctx.switchToHttp().getRequest();
const cookies = cookie.parse(request.headers.cookie || '');
const token = cookies[KINDE_ACCESS_TOKEN] ?? null;
let token = cookies[KINDE_ACCESS_TOKEN] ?? '';
const authHeader = request.headers.authorization;
if (authHeader && authHeader.startsWith('Bearer ')) {
token = authHeader.substring(7);
}
const headers = {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
};
const profile = await axios.get(
const response = await axios.get(
`${getEnvSafely(KINDE_DOMAIN_URL)}/oauth2/user_profile`,
{
headers,
},
);
if (profile.status === 200) {
return profile.data;
if (response.status === 200) {
return response.data;
}
} catch (error) {
throw new Error('Error getting user');
Expand Down
35 changes: 32 additions & 3 deletions src/guards/abstract.guard.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import jwt from 'jsonwebtoken';
import JwksClient from 'jwks-rsa';
import * as cookie from 'cookie';
import { KindePayload } from '../lib/kinde.interface';
import { CanActivate, ExecutionContext } from '@nestjs/common';
import {
CanActivate,
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
import { getEnvSafely } from '../lib/kinde.factory';
import { KINDE_DOMAIN_URL } from '../lib/kinde.constant';
import { KINDE_ACCESS_TOKEN, KINDE_DOMAIN_URL } from '../lib/kinde.constant';

type TokenCallback = (err: Error | null, key?: string) => void;

Expand Down Expand Up @@ -31,10 +36,11 @@ export abstract class AbstractGuard implements CanActivate {

/**
* Verifies the given token.
*
* @param token - The token to be verified.
* @returns A promise that resolves to the decoded token if verification is successful, or rejects with an error if verification fails.
*/
protected verifyToken(token?: string): Promise<KindePayload> {
private verifyToken(token?: string): Promise<KindePayload> {
return new Promise((resolve, reject) => {
if (!token) return reject(new Error('No JWT token provided!'));
jwt.verify(token, this.getKey, {}, (err, decoded) => {
Expand All @@ -43,4 +49,27 @@ export abstract class AbstractGuard implements CanActivate {
});
});
}

/**
* Decodes the token from the request.
*
* @param context - The execution context of the request.
* @returns A promise that resolves to the decoded token.
*/
protected async decodeToken(
context: ExecutionContext,
): Promise<KindePayload> {
const request = context.switchToHttp().getRequest();
const cookies = cookie.parse(request.headers.cookie || '');
let token = cookies[KINDE_ACCESS_TOKEN] ?? '';
const authHeader = request.headers.authorization;
if (authHeader && authHeader.startsWith('Bearer ')) {
token = authHeader.substring(7);
}
const decoded = await this.verifyToken(token);
if (!decoded) {
throw new UnauthorizedException();
}
return decoded;
}
}
14 changes: 2 additions & 12 deletions src/guards/isAuth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ import {
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
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 {
Expand All @@ -21,17 +19,9 @@ export class IsAuthGuard extends AbstractGuard {
if (!auth) {
return true;
}
const request = context.switchToHttp().getRequest();
const cookies = cookie.parse(request.headers.cookie || '');
const decoded = await this.verifyToken(cookies[KINDE_ACCESS_TOKEN]);
if (!decoded) {
throw new UnauthorizedException();
}
return true;
return !!(await this.decodeToken(context));
} catch (error) {
throw new UnauthorizedException({
message: error ? String(error) : 'Unauthorized',
});
throw new UnauthorizedException();
}
}
}
13 changes: 2 additions & 11 deletions src/guards/permissions.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ import {
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
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 {
Expand All @@ -24,12 +22,7 @@ export class PermissionsGuard extends AbstractGuard {
if (!permissions) {
return true;
}
const request = context.switchToHttp().getRequest();
const cookies = cookie.parse(request.headers.cookie || '');
const decoded = await this.verifyToken(cookies[KINDE_ACCESS_TOKEN]);
if (!decoded) {
throw new UnauthorizedException();
}
const decoded = await this.decodeToken(context);
const userPermissions = decoded['x-hasura-permissions'];
if (!userPermissions) {
throw new UnauthorizedException();
Expand All @@ -38,9 +31,7 @@ export class PermissionsGuard extends AbstractGuard {
userPermissions.includes(permission),
);
} catch (error) {
throw new UnauthorizedException({
message: error ? String(error) : 'Unauthorized',
});
throw new UnauthorizedException();
}
}
}
14 changes: 3 additions & 11 deletions src/guards/roles.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ import {
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
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 {
Expand All @@ -21,21 +19,15 @@ export class RolesGuard extends AbstractGuard {
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const cookies = cookie.parse(request.headers.cookie || '');
const decoded = await this.verifyToken(cookies[KINDE_ACCESS_TOKEN]);
if (!decoded) {
throw new UnauthorizedException();
}

const decoded = await this.decodeToken(context);
const userRoles = decoded['x-hasura-roles']?.map((role) => role.name);
if (!userRoles) {
throw new UnauthorizedException();
}
return roles.some((role) => userRoles.includes(role));
} catch (error) {
throw new UnauthorizedException({
message: error ? String(error) : 'Unauthorized',
});
throw new UnauthorizedException();
}
}
}

0 comments on commit 06ba0ff

Please sign in to comment.