From 01ea05f01314d191daa468b353cf0795ba69cf28 Mon Sep 17 00:00:00 2001 From: Nathnael Date: Tue, 25 Aug 2026 12:00:43 +0000 Subject: [PATCH] fix(auth): keep secondary positions in permission checks IAM lets an employee hold several positions, but the vendored JwtGuard collapses employee.positions[] down to a single employee.position and drops the rest. Non-delegate secondary positions vanished entirely, so staff on two posts resolved to one post's permissions and every check on the other rejected them. FreightJwtGuard re-attaches the full list from the same session snapshot the parent guard already read, so nothing extra is fetched per request beyond a cached session lookup. employee.position is left untouched, keeping audit logging and delegation unaffected. collectPermissionKeys and collectPositionTypeKeys now union across every position, and /me returns them all. Verified against a real two-position user (djibouti-gl-director + djibouti-gl-chief) on the local dev database: /me positions 1 -> 2 /me permissionKeys 17 -> 28 GET /api/interchange-documents 403 -> 200 GET /api/trains 403 -> 200 11 permissions recovered, none lost. Six single-position users return byte-identical payloads before and after. --- .../src/common/booking-guards.ts | 10 +- .../src/common/freight-jwt.guard.ts | 101 ++++++++++++++++++ .../common/freight-permission.util.spec.ts | 64 +++++++++++ .../src/common/freight-permission.util.ts | 26 ++++- .../src/common/rule-engine-guards.ts | 12 +-- .../src/modules/auth/account.controller.ts | 4 +- .../src/modules/auth/freight-me.controller.ts | 4 +- .../src/modules/auth/freight-me.service.ts | 95 +++++++++------- .../src/modules/chat/chat.controller.ts | 4 +- .../src/modules/exports/exports.controller.ts | 4 +- .../notification-inbox.controller.ts | 4 +- .../modules/verifayda/verifayda.controller.ts | 4 +- 12 files changed, 265 insertions(+), 67 deletions(-) create mode 100644 apps/edr-freight-api/src/common/freight-jwt.guard.ts diff --git a/apps/edr-freight-api/src/common/booking-guards.ts b/apps/edr-freight-api/src/common/booking-guards.ts index 68bbdcba4..603811178 100644 --- a/apps/edr-freight-api/src/common/booking-guards.ts +++ b/apps/edr-freight-api/src/common/booking-guards.ts @@ -1,5 +1,5 @@ import { applyDecorators, UseGuards } from '@nestjs/common'; -import { JwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard'; +import { FreightJwtGuard } from './freight-jwt.guard'; import { FreightPermissionGuard, @@ -11,7 +11,7 @@ import { FREIGHT_PERMS } from '../seed/freight-permissions.registry'; export const BookingStaff = (permission: string | string[]) => applyDecorators( UseGuards( - JwtGuard, + FreightJwtGuard, FreightPermissionGuard( Array.isArray(permission) ? permission : [permission], ), @@ -26,11 +26,11 @@ export const BookingStaff = (permission: string | string[]) => * BookingStaff() or MixedAudience(); kept for routes not yet swept. */ export const StaffReference = () => - applyDecorators(UseGuards(JwtGuard, FreightPermissionGuard([]))); + applyDecorators(UseGuards(FreightJwtGuard, FreightPermissionGuard([]))); /** Portal routes: customer accounts only; ownership scoping stays in services. */ export const PortalCustomer = () => - applyDecorators(UseGuards(JwtGuard, PortalCustomerGuard)); + applyDecorators(UseGuards(FreightJwtGuard, PortalCustomerGuard)); /** * Routes both audiences call (sign, shared document reads, handover): staff @@ -40,7 +40,7 @@ export const PortalCustomer = () => export const MixedAudience = (permission: string | string[]) => applyDecorators( UseGuards( - JwtGuard, + FreightJwtGuard, MixedAudienceGuard( Array.isArray(permission) ? permission : [permission], ), diff --git a/apps/edr-freight-api/src/common/freight-jwt.guard.ts b/apps/edr-freight-api/src/common/freight-jwt.guard.ts new file mode 100644 index 000000000..68b842217 --- /dev/null +++ b/apps/edr-freight-api/src/common/freight-jwt.guard.ts @@ -0,0 +1,101 @@ +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { InjectDataSource } from '@nestjs/typeorm'; +import { JwtGuard as IamJwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard'; +import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type'; +import { DataSource } from 'typeorm'; + +/** One position as the login snapshot stores it (`iam.sessions.userInfo`). */ +type SnapshotPosition = { id?: string; [key: string]: unknown }; + +type SessionUserInfo = { + employee?: { id?: string; positions?: SnapshotPosition[] }[]; +}; + +/** + * Like the IAM JwtGuard, but keeps the caller's SECONDARY positions. + * + * IAM models an employee as holding many positions, and the login snapshot in + * `iam.sessions.userInfo` carries all of them. `JwtGuard.parseToken` then + * collapses that to a single `employee.position` — whichever the request + * headers select, else `positions[0]` — and drops the rest. Non-delegate + * secondary positions vanish entirely, so staff holding two posts resolve to + * only one post's permissions and every check on the other one rejects them. + * + * This re-attaches the full list as `employee.positions`. `employee.position` + * is left exactly as the parent set it, so everything reading the single + * position today (audit log, delegation deadline) is unaffected; only the + * permission utils, which prefer the array, see the difference. + */ +@Injectable() +export class FreightJwtGuard extends IamJwtGuard implements CanActivate { + // ponytail: unbounded-until-TTL map, cleared wholesale when it gets big. + // Sessions are few and the value is small; swap for an LRU if that changes. + private static readonly CACHE_TTL_MS = 30_000; + private static readonly CACHE_MAX_ENTRIES = 5_000; + private readonly cache = new Map< + string, + { positions: SnapshotPosition[]; expiresAt: number } + >(); + + constructor( + reflector: Reflector, + @InjectDataSource() private readonly ds: DataSource, + ) { + super(reflector, ds); + } + + async canActivate(context: ExecutionContext): Promise { + if (!(await super.canActivate(context))) return false; + + const user = context.switchToHttp().getRequest().user as + | TCurrentUser + | undefined; + const employee = user?.employee; + if (!employee || !user?.sessionId) return true; + + const positions = await this.positionsForSession( + user.sessionId, + employee.id, + ); + // Never blank out what the parent resolved: an unreadable session or a + // snapshot without positions must degrade to the single-position + // behaviour, not to no positions at all. + if (positions.length) { + (employee as { positions?: SnapshotPosition[] }).positions = positions; + } + return true; + } + + /** Every position the login snapshot holds for this employee. */ + private async positionsForSession( + sessionId: string, + employeeId: string | undefined, + ): Promise { + const now = Date.now(); + const hit = this.cache.get(sessionId); + if (hit && hit.expiresAt > now) return hit.positions; + + let positions: SnapshotPosition[] = []; + try { + const rows: { userInfo: SessionUserInfo | null }[] = await this.ds.query( + `SELECT "userInfo" FROM iam.sessions WHERE id = $1`, + [sessionId], + ); + const employees = rows[0]?.userInfo?.employee ?? []; + const match = + employees.find((e) => e?.id && e.id === employeeId) ?? employees[0]; + positions = match?.positions ?? []; + } catch { + return []; // iam unreachable — caller keeps the parent's single position + } + + if (this.cache.size >= FreightJwtGuard.CACHE_MAX_ENTRIES) + this.cache.clear(); + this.cache.set(sessionId, { + positions, + expiresAt: now + FreightJwtGuard.CACHE_TTL_MS, + }); + return positions; + } +} diff --git a/apps/edr-freight-api/src/common/freight-permission.util.spec.ts b/apps/edr-freight-api/src/common/freight-permission.util.spec.ts index f3931f78a..562b21156 100644 --- a/apps/edr-freight-api/src/common/freight-permission.util.spec.ts +++ b/apps/edr-freight-api/src/common/freight-permission.util.spec.ts @@ -2,6 +2,7 @@ import { assertCanApproveContractStep, canEditContractStep, collectPermissionKeys, + collectPositionTypeKeys, hasFreightPermission, setPositionTypePermissionResolver, } from './freight-permission.util'; @@ -121,3 +122,66 @@ describe('collectPermissionKeys — position-type grants', () => { expect(hasFreightPermission(direct, CLEARANCE)).toBe(true); }); }); + +/** + * IAM lets an employee hold several positions, but the vendored `JwtGuard` + * collapses `employee.positions[]` down to a single `employee.position` and + * drops the rest — so staff on two posts resolved to one post's permissions + * and every check on the other rejected them. `FreightJwtGuard` restores the + * full list as `employee.positions`; these cover the union that depends on it. + */ +describe('multiple positions', () => { + // Shaped like the real two-post employee: GL chief AND GL director. + const twoPost = { + employee: { + // What the vendored guard leaves behind — one of the two, arbitrarily. + position: { + positionType: { key: 'djibouti-gl-chief' }, + permissions: [{ key: FREIGHT_PERMS.contracts.view }], + }, + // What FreightJwtGuard puts back. + positions: [ + { + positionType: { key: 'djibouti-gl-chief' }, + permissions: [{ key: FREIGHT_PERMS.contracts.view }], + }, + { + positionType: { key: 'djibouti-gl-director' }, + permissions: [{ key: FREIGHT_PERMS.bookings.view }], + }, + ], + }, + }; + + it('unions permissions across every position', () => { + const keys = collectPermissionKeys(twoPost); + expect(keys).toContain(FREIGHT_PERMS.contracts.view); + expect(keys).toContain(FREIGHT_PERMS.bookings.view); + }); + + it('grants the secondary position’s permission, not just the first', () => { + expect(hasFreightPermission(twoPost, FREIGHT_PERMS.bookings.view)).toBe(true); + }); + + it('answers to both position types', () => { + expect(collectPositionTypeKeys(twoPost)).toEqual( + expect.arrayContaining(['djibouti-gl-chief', 'djibouti-gl-director']), + ); + }); + + it('does not double-count the position the guard also left singular', () => { + const keys = collectPermissionKeys(twoPost); + expect(keys.filter((k) => k === FREIGHT_PERMS.contracts.view)).toHaveLength(1); + }); + + it('still resolves the single position when the array is absent', () => { + // A request that skipped FreightJwtGuard must degrade to the old behaviour, + // not to no permissions at all. + const onePost = { + employee: { + position: { permissions: [{ key: FREIGHT_PERMS.contracts.view }] }, + }, + }; + expect(hasFreightPermission(onePost, FREIGHT_PERMS.contracts.view)).toBe(true); + }); +}); diff --git a/apps/edr-freight-api/src/common/freight-permission.util.ts b/apps/edr-freight-api/src/common/freight-permission.util.ts index bc98a6df4..1078c5ad9 100644 --- a/apps/edr-freight-api/src/common/freight-permission.util.ts +++ b/apps/edr-freight-api/src/common/freight-permission.util.ts @@ -17,6 +17,15 @@ type MeLikeUser = { permissions?: PermissionLike[]; positionType?: PositionTypeLike | null; }; + /** + * Every position the employee holds, restored by `FreightJwtGuard` + * from the login snapshot. The IAM guard only ever sets the singular + * `position` above; without this, a second post's grants are invisible. + */ + positions?: { + permissions?: PermissionLike[]; + positionType?: PositionTypeLike | null; + }[]; delegatedPositions?: { permissions?: PermissionLike[] }[]; } | { @@ -98,10 +107,15 @@ export function collectPermissionKeys(user: MeLikeUser | null | undefined): stri return [...keys]; } - for (const p of employee.position?.permissions ?? []) { - if (p.key) keys.add(p.key); + // `position` is whichever single post the IAM guard selected; `positions` is + // the full set FreightJwtGuard restores. Walk both — the array is absent on + // a session the guard could not re-read, and the two overlap harmlessly. + for (const pos of [employee.position, ...(employee.positions ?? [])]) { + for (const p of pos?.permissions ?? []) { + if (p.key) keys.add(p.key); + } + addTypePermissions(pos?.positionType); } - addTypePermissions(employee.position?.positionType); for (const delegated of employee.delegatedPositions ?? []) { for (const p of delegated.permissions ?? []) { if (p.key) keys.add(p.key); @@ -158,8 +172,10 @@ export function collectPositionTypeKeys( return [...keys]; } - if (employee.position?.positionType?.key) { - keys.add(employee.position.positionType.key); + // Both shapes, same reason as collectPermissionKeys: an employee holding two + // posts answers to both their position types. + for (const pos of [employee.position, ...(employee.positions ?? [])]) { + if (pos?.positionType?.key) keys.add(pos.positionType.key); } return [...keys]; } diff --git a/apps/edr-freight-api/src/common/rule-engine-guards.ts b/apps/edr-freight-api/src/common/rule-engine-guards.ts index ba8096b5b..d7297d3b5 100644 --- a/apps/edr-freight-api/src/common/rule-engine-guards.ts +++ b/apps/edr-freight-api/src/common/rule-engine-guards.ts @@ -1,5 +1,5 @@ import { applyDecorators, UseGuards } from '@nestjs/common'; -import { JwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard'; +import { FreightJwtGuard } from './freight-jwt.guard'; import { FreightPermissionGuard } from './freight-permission.guard'; import { @@ -10,7 +10,7 @@ import { export const RuleEngineView = (slug: RuleEngineResourceSlug) => applyDecorators( - UseGuards(JwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.view(slug)])), + UseGuards(FreightJwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.view(slug)])), ); // Granular CRUD replaces the retired coarse RuleEngineManage. Each write @@ -18,17 +18,17 @@ export const RuleEngineView = (slug: RuleEngineResourceSlug) => // update on PATCH / reorder / move-order, delete on DELETE. export const RuleEngineCreate = (slug: RuleEngineResourceSlug) => applyDecorators( - UseGuards(JwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.create(slug)])), + UseGuards(FreightJwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.create(slug)])), ); export const RuleEngineUpdate = (slug: RuleEngineResourceSlug) => applyDecorators( - UseGuards(JwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.update(slug)])), + UseGuards(FreightJwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.update(slug)])), ); export const RuleEngineDelete = (slug: RuleEngineResourceSlug) => applyDecorators( - UseGuards(JwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.delete(slug)])), + UseGuards(FreightJwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.delete(slug)])), ); /** @@ -38,5 +38,5 @@ export const RuleEngineDelete = (slug: RuleEngineResourceSlug) => */ export const RuleEngineApprove = (slug: RuleEngineApprovableSlug) => applyDecorators( - UseGuards(JwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.approve(slug)])), + UseGuards(FreightJwtGuard, FreightPermissionGuard([FREIGHT_PERMS.ruleEngine.approve(slug)])), ); diff --git a/apps/edr-freight-api/src/modules/auth/account.controller.ts b/apps/edr-freight-api/src/modules/auth/account.controller.ts index d7d7f15c3..96f90e8a3 100644 --- a/apps/edr-freight-api/src/modules/auth/account.controller.ts +++ b/apps/edr-freight-api/src/modules/auth/account.controller.ts @@ -1,7 +1,7 @@ import { Body, Controller, Patch, Post, UseGuards } from "@nestjs/common"; import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger"; import { CurrentUser } from "@tria-plc/api-common/modules/auth/decorators/current-user.decorator"; -import { JwtGuard } from "@tria-plc/api-common/modules/auth/services/jwt.guard"; +import { FreightJwtGuard } from "../../common/freight-jwt.guard"; import type { TCurrentUser } from "@tria-plc/api-common/modules/auth/types/current-user.type"; import { AccountService } from "./account.service"; @@ -19,7 +19,7 @@ import { @ApiTags("auth") @Controller("me") @ApiBearerAuth() -@UseGuards(JwtGuard) +@UseGuards(FreightJwtGuard) export class AccountController { constructor(private readonly accountService: AccountService) {} diff --git a/apps/edr-freight-api/src/modules/auth/freight-me.controller.ts b/apps/edr-freight-api/src/modules/auth/freight-me.controller.ts index b85ecea84..f1c974687 100644 --- a/apps/edr-freight-api/src/modules/auth/freight-me.controller.ts +++ b/apps/edr-freight-api/src/modules/auth/freight-me.controller.ts @@ -1,7 +1,7 @@ import { Controller, Get, UseGuards } from '@nestjs/common'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { CurrentUser } from '@tria-plc/api-common/modules/auth/decorators/current-user.decorator'; -import { JwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard'; +import { FreightJwtGuard } from '../../common/freight-jwt.guard'; import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type'; import { FreightMeService } from './freight-me.service'; @@ -13,7 +13,7 @@ export class FreightMeController { constructor(private readonly freightMeService: FreightMeService) {} @Get() - @UseGuards(JwtGuard) + @UseGuards(FreightJwtGuard) @ApiOperation({ summary: 'Current user with flat permissionKeys for backoffice gating', }) diff --git a/apps/edr-freight-api/src/modules/auth/freight-me.service.ts b/apps/edr-freight-api/src/modules/auth/freight-me.service.ts index 6bcfd964d..b897c5fef 100644 --- a/apps/edr-freight-api/src/modules/auth/freight-me.service.ts +++ b/apps/edr-freight-api/src/modules/auth/freight-me.service.ts @@ -9,6 +9,9 @@ import { } from '../../common/freight-permission.util'; import { PERMISSIONS_CATALOG } from '../../seed/freight-permissions.registry'; +/** One position as the session snapshot carries it. */ +type TokenPosition = NonNullable['position']; + @Injectable() export class FreightMeService { constructor(@InjectDataSource() private readonly dataSource: DataSource) {} @@ -65,49 +68,63 @@ export class FreightMeService { } async getEnrichedProfile(user: TCurrentUser) { - const positionId = user.employee?.position?.id; - const [positionType, positionTypePermissionKeys] = await Promise.all([ - this.lookupPositionType(positionId), - this.lookupPositionTypePermissions(positionId), - ]); + const employeeRecord = user.employee as + | (typeof user.employee & { positions?: TokenPosition[] }) + | undefined; - // Merge the type-level grants into the position's own permission list so - // BOTH consumers see them: `collectPermissionKeys` below, and the - // backoffice's `getPermissionKeys`, which walks this same nested array. - const positionPermissions = [ - ...(user.employee?.position?.permissions ?? []), - ]; - const seenPermissionKeys = new Set( - positionPermissions.map((p) => p?.key).filter(Boolean), + // `FreightJwtGuard` restores every position the login snapshot holds; the + // stock IAM guard only ever leaves the single `position`. Fall back to it + // so a request that somehow skipped our guard still resolves one post + // rather than none. + const rawPositions: TokenPosition[] = employeeRecord?.positions?.length + ? employeeRecord.positions + : employeeRecord?.position + ? [employeeRecord.position] + : []; + + const enrichedPositions = await Promise.all( + rawPositions.map(async (position) => { + const [positionType, positionTypePermissionKeys] = await Promise.all([ + this.lookupPositionType(position.id), + this.lookupPositionTypePermissions(position.id), + ]); + + // Merge the type-level grants into this position's own permission list + // so BOTH consumers see them: `collectPermissionKeys` below, and the + // backoffice's `getPermissionKeys`, which walks this nested array. + const permissions = [...(position.permissions ?? [])]; + const seen = new Set(permissions.map((p) => p?.key).filter(Boolean)); + for (const key of positionTypePermissionKeys) { + if (!seen.has(key)) { + seen.add(key); + permissions.push({ key } as (typeof permissions)[number]); + } + } + + return { + positionTypePermissionKeys, + position: { + id: position.id, + key: position.key, + employeePositionId: position.employeePositionId, + name: position.name, + isDelegate: position.isDelegate, + parentPositionId: position.parentPositionId, + permissions, + positionType, + }, + }; + }), ); - for (const key of positionTypePermissionKeys) { - if (!seenPermissionKeys.has(key)) { - seenPermissionKeys.add(key); - positionPermissions.push({ key } as (typeof positionPermissions)[number]); - } - } - const employee = user.employee + const employee = employeeRecord ? [ { - id: user.employee.id, - organizationId: user.employee.organizationId, - unitId: user.employee.unitId, - name: user.employee.name, - positions: user.employee.position - ? [ - { - id: user.employee.position.id, - key: user.employee.position.key, - employeePositionId: user.employee.position.employeePositionId, - name: user.employee.position.name, - isDelegate: user.employee.position.isDelegate, - parentPositionId: user.employee.position.parentPositionId, - permissions: positionPermissions, - positionType, - }, - ] - : [], + id: employeeRecord.id, + organizationId: employeeRecord.organizationId, + unitId: employeeRecord.unitId, + name: employeeRecord.name, + positions: enrichedPositions.map((p) => p.position), }, ] : []; @@ -118,7 +135,7 @@ export class FreightMeService { const permissionKeys = [ ...new Set([ ...collectPermissionKeys(user), - ...positionTypePermissionKeys, + ...enrichedPositions.flatMap((p) => p.positionTypePermissionKeys), ]), ]; diff --git a/apps/edr-freight-api/src/modules/chat/chat.controller.ts b/apps/edr-freight-api/src/modules/chat/chat.controller.ts index 0ecca04c0..5e122bdd2 100644 --- a/apps/edr-freight-api/src/modules/chat/chat.controller.ts +++ b/apps/edr-freight-api/src/modules/chat/chat.controller.ts @@ -1,7 +1,7 @@ import { Controller, Get, Post, UseGuards } from '@nestjs/common'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { CurrentUser } from '@tria-plc/api-common/modules/auth/decorators/current-user.decorator'; -import { JwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard'; +import { FreightJwtGuard } from '../../common/freight-jwt.guard'; import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type'; import { ChatSync } from '../../common/booking-guards'; @@ -18,7 +18,7 @@ export class ChatController { ) {} @Get('sso') - @UseGuards(JwtGuard) + @UseGuards(FreightJwtGuard) @ApiOperation({ summary: 'One-click sign-in link into EDR internal chat' }) getSso(@CurrentUser() user: TCurrentUser) { return this.sso.getSsoUrl(user); diff --git a/apps/edr-freight-api/src/modules/exports/exports.controller.ts b/apps/edr-freight-api/src/modules/exports/exports.controller.ts index 89ca7419a..aea35a9bc 100644 --- a/apps/edr-freight-api/src/modules/exports/exports.controller.ts +++ b/apps/edr-freight-api/src/modules/exports/exports.controller.ts @@ -3,7 +3,7 @@ import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { InjectDataSource } from '@nestjs/typeorm'; import { DataSource } from 'typeorm'; import { CurrentUser } from '@edr/api-common'; -import { JwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard'; +import { FreightJwtGuard } from '../../common/freight-jwt.guard'; import type { Response } from 'express'; import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type'; @@ -57,7 +57,7 @@ const toCatalogEntry = (dataset: ExportDataset): ExportCatalogEntry => ({ @ApiTags('Exports') @ApiBearerAuth() @Controller('exports') -@UseGuards(JwtGuard) +@UseGuards(FreightJwtGuard) export class ExportsController { constructor( private readonly runner: ExportRunnerService, diff --git a/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.controller.ts b/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.controller.ts index 6fb82c3a0..16026cc96 100644 --- a/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.controller.ts +++ b/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.controller.ts @@ -10,7 +10,7 @@ import { UseGuards, } from "@nestjs/common"; import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger"; -import { JwtGuard } from "@tria-plc/api-common/modules/auth/services/jwt.guard"; +import { FreightJwtGuard } from "../../common/freight-jwt.guard"; import { AuthUserPayload, @@ -21,7 +21,7 @@ import { NotificationInboxService } from "./notification-inbox.service"; @ApiTags("notifications") @ApiBearerAuth() -@UseGuards(JwtGuard) +@UseGuards(FreightJwtGuard) @Controller("notifications") export class NotificationInboxController { constructor(private readonly service: NotificationInboxService) {} diff --git a/apps/edr-freight-api/src/modules/verifayda/verifayda.controller.ts b/apps/edr-freight-api/src/modules/verifayda/verifayda.controller.ts index 977e677f8..3a94bb05a 100644 --- a/apps/edr-freight-api/src/modules/verifayda/verifayda.controller.ts +++ b/apps/edr-freight-api/src/modules/verifayda/verifayda.controller.ts @@ -17,7 +17,7 @@ import { } from '@nestjs/swagger'; import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type'; import { IsPublic } from '@tria-plc/api-common/modules/auth/decorators/public.decorator'; -import { JwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard'; +import { FreightJwtGuard } from '../../common/freight-jwt.guard'; import { OptionalJwtGuard } from './optional-jwt.guard'; import { CompleteVerificationResultDto, @@ -91,7 +91,7 @@ export class VerifaydaController { } @Get('status') - @UseGuards(JwtGuard) + @UseGuards(FreightJwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: "Get the current user's Fayda verification status",