fix(auth): add local JwtStrategy to all services, fix @genex/common import

6 services (user/issuer/clearing/compliance/notification/telemetry) were
missing JwtStrategy provider, causing 'Unknown authentication strategy jwt'
500 errors on all auth-protected endpoints.

- Create infrastructure/strategies/jwt.strategy.ts in each service
- Update each module to import from local path (not @genex/common)
- Revert @genex/common/index.ts strategy export (passport-jwt not in each
  service's node_modules, causes runtime 'Cannot find module' error)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-03-04 23:00:39 -08:00
parent 75ed31cc04
commit 3b733462ce
12 changed files with 96 additions and 9 deletions

View File

@ -8,9 +8,6 @@ export * from './decorators/roles.decorator';
export * from './guards/jwt-auth.guard'; export * from './guards/jwt-auth.guard';
export * from './guards/roles.guard'; export * from './guards/roles.guard';
// Strategies
export * from './strategies/jwt.strategy';
// Interceptors // Interceptors
export * from './interceptors/logging.interceptor'; export * from './interceptors/logging.interceptor';
export * from './interceptors/transform.interceptor'; export * from './interceptors/transform.interceptor';

View File

@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from '@genex/common'; import { JwtStrategy } from './infrastructure/strategies/jwt.strategy';
// Domain entities // Domain entities
import { Settlement } from './domain/entities/settlement.entity'; import { Settlement } from './domain/entities/settlement.entity';

View File

@ -0,0 +1,18 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_ACCESS_SECRET || 'dev-access-secret',
});
}
async validate(payload: { sub: string; role: string; kycLevel: number; type: string }) {
return { sub: payload.sub, role: payload.role, kycLevel: payload.kycLevel };
}
}

View File

@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from '@genex/common'; import { JwtStrategy } from './infrastructure/strategies/jwt.strategy';
// ─── Domain Entities ─── // ─── Domain Entities ───
import { AmlAlert } from './domain/entities/aml-alert.entity'; import { AmlAlert } from './domain/entities/aml-alert.entity';

View File

@ -0,0 +1,18 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_ACCESS_SECRET || 'dev-access-secret',
});
}
async validate(payload: { sub: string; role: string; kycLevel: number; type: string }) {
return { sub: payload.sub, role: payload.role, kycLevel: payload.kycLevel };
}
}

View File

@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from '@genex/common'; import { JwtStrategy } from './infrastructure/strategies/jwt.strategy';
// Domain entities // Domain entities
import { Issuer } from './domain/entities/issuer.entity'; import { Issuer } from './domain/entities/issuer.entity';

View File

@ -0,0 +1,18 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_ACCESS_SECRET || 'dev-access-secret',
});
}
async validate(payload: { sub: string; role: string; kycLevel: number; type: string }) {
return { sub: payload.sub, role: payload.role, kycLevel: payload.kycLevel };
}
}

View File

@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from '@genex/common'; import { JwtStrategy } from './infrastructure/strategies/jwt.strategy';
// Domain entities // Domain entities
import { Notification } from './domain/entities/notification.entity'; import { Notification } from './domain/entities/notification.entity';

View File

@ -0,0 +1,18 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_ACCESS_SECRET || 'dev-access-secret',
});
}
async validate(payload: { sub: string; role: string; kycLevel: number; type: string }) {
return { sub: payload.sub, role: payload.role, kycLevel: payload.kycLevel };
}
}

View File

@ -3,7 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { ScheduleModule } from '@nestjs/schedule'; import { ScheduleModule } from '@nestjs/schedule';
import { JwtStrategy } from '@genex/common'; import { JwtStrategy } from './infrastructure/strategies/jwt.strategy';
// Domain entities // Domain entities
import { TelemetryEvent } from './domain/entities/telemetry-event.entity'; import { TelemetryEvent } from './domain/entities/telemetry-event.entity';

View File

@ -0,0 +1,18 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_ACCESS_SECRET || 'dev-access-secret',
});
}
async validate(payload: { sub: string; role: string; kycLevel: number; type: string }) {
return { sub: payload.sub, role: payload.role, kycLevel: payload.kycLevel };
}
}

View File

@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from '@genex/common'; import { JwtStrategy } from './infrastructure/strategies/jwt.strategy';
// Domain entities // Domain entities
import { User } from './domain/entities/user.entity'; import { User } from './domain/entities/user.entity';