fix: per-service JWT in Kong, fix auth-service tenant-aware repos

- Replace global JWT plugin with per-service JWT (skip auth-service)
  to fix auth routes being blocked by global JWT in DB-less mode
- Fix UserRepository and ApiKeyRepository to use standard TypeORM
  instead of TenantAwareRepository (users are global, not per-schema)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-21 23:31:32 -08:00
parent 7dd7de4a22
commit c710303b60
3 changed files with 86 additions and 26 deletions

View File

@ -106,12 +106,7 @@ services:
strip_path: false strip_path: false
plugins: plugins:
- name: jwt # ===== Global plugins (apply to ALL routes) =====
config:
key_claim_name: kid
claims_to_verify:
- exp
- name: cors - name: cors
config: config:
origins: origins:
@ -143,10 +138,64 @@ plugins:
path: /dev/stdout path: /dev/stdout
reopen: true reopen: true
# ===== JWT per-service (NOT on auth-service) =====
- name: jwt - name: jwt
route: auth-routes service: agent-service
enabled: false config:
key_claim_name: kid
claims_to_verify:
- exp
- name: jwt
service: agent-config-service
config:
key_claim_name: kid
claims_to_verify:
- exp
- name: jwt
service: ops-service
config:
key_claim_name: kid
claims_to_verify:
- exp
- name: jwt
service: inventory-service
config:
key_claim_name: kid
claims_to_verify:
- exp
- name: jwt
service: monitor-service
config:
key_claim_name: kid
claims_to_verify:
- exp
- name: jwt
service: comm-service
config:
key_claim_name: kid
claims_to_verify:
- exp
- name: jwt
service: voice-service
config:
key_claim_name: kid
claims_to_verify:
- exp
- name: jwt
service: audit-service
config:
key_claim_name: kid
claims_to_verify:
- exp
# ===== Route-specific overrides =====
- name: rate-limiting - name: rate-limiting
route: agent-ws route: agent-ws
config: config:

View File

@ -1,21 +1,24 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { TenantAwareRepository } from '@it0/database'; import { Repository } from 'typeorm';
import { ApiKey } from '../../domain/entities/api-key.entity'; import { ApiKey } from '../../domain/entities/api-key.entity';
@Injectable() @Injectable()
export class ApiKeyRepository extends TenantAwareRepository<ApiKey> { export class ApiKeyRepository {
constructor(dataSource: DataSource) { constructor(
super(dataSource, ApiKey); @InjectRepository(ApiKey)
} private readonly repo: Repository<ApiKey>,
) {}
async findByKeyHash(keyHash: string): Promise<ApiKey | null> { async findByKeyHash(keyHash: string): Promise<ApiKey | null> {
const repo = await this.getRepository(); return this.repo.findOneBy({ keyHash });
return repo.findOneBy({ keyHash } as any);
} }
async findByUserId(userId: string): Promise<ApiKey[]> { async findByUserId(userId: string): Promise<ApiKey[]> {
const repo = await this.getRepository(); return this.repo.find({ where: { userId } });
return repo.find({ where: { userId } as any }); }
async save(apiKey: ApiKey): Promise<ApiKey> {
return this.repo.save(apiKey);
} }
} }

View File

@ -1,16 +1,24 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { TenantAwareRepository } from '@it0/database'; import { Repository } from 'typeorm';
import { User } from '../../domain/entities/user.entity'; import { User } from '../../domain/entities/user.entity';
@Injectable() @Injectable()
export class UserRepository extends TenantAwareRepository<User> { export class UserRepository {
constructor(dataSource: DataSource) { constructor(
super(dataSource, User); @InjectRepository(User)
} private readonly repo: Repository<User>,
) {}
async findByEmail(email: string): Promise<User | null> { async findByEmail(email: string): Promise<User | null> {
const repo = await this.getRepository(); return this.repo.findOneBy({ email });
return repo.findOneBy({ email } as any); }
async findById(id: string): Promise<User | null> {
return this.repo.findOneBy({ id });
}
async save(user: User): Promise<User> {
return this.repo.save(user);
} }
} }