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
plugins:
- name: jwt
config:
key_claim_name: kid
claims_to_verify:
- exp
# ===== Global plugins (apply to ALL routes) =====
- name: cors
config:
origins:
@ -143,10 +138,64 @@ plugins:
path: /dev/stdout
reopen: true
# ===== JWT per-service (NOT on auth-service) =====
- name: jwt
route: auth-routes
enabled: false
service: agent-service
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
route: agent-ws
config:

View File

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

View File

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