@tsdevstack/nest-common 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/auth/auth-user.interface.d.ts +62 -0
  4. package/dist/auth/auth.guard.d.ts +181 -0
  5. package/dist/auth/auth.guard.test.d.ts +1 -0
  6. package/dist/auth/auth.module.d.ts +45 -0
  7. package/dist/auth/index.d.ts +17 -0
  8. package/dist/auth/partner-api.decorator.d.ts +42 -0
  9. package/dist/auth/partner.decorator.d.ts +60 -0
  10. package/dist/auth/partner.decorator.test.d.ts +1 -0
  11. package/dist/auth/public.decorator.d.ts +42 -0
  12. package/dist/auth/public.decorator.test.d.ts +1 -0
  13. package/dist/auth/utils/extract-user-from-headers.d.ts +45 -0
  14. package/dist/auth/utils/extract-user-from-headers.test.d.ts +1 -0
  15. package/dist/auth/utils/index.d.ts +8 -0
  16. package/dist/auth/utils/parse-header-value.d.ts +40 -0
  17. package/dist/auth/utils/parse-header-value.test.d.ts +1 -0
  18. package/dist/auth/utils/to-camel-case.d.ts +18 -0
  19. package/dist/auth/utils/to-camel-case.test.d.ts +1 -0
  20. package/dist/bootstrap/create-app.d.ts +31 -0
  21. package/dist/bootstrap/create-app.test.d.ts +1 -0
  22. package/dist/bootstrap/start-worker.d.ts +24 -0
  23. package/dist/bootstrap/start-worker.test.d.ts +1 -0
  24. package/dist/bull/bull-config.module.d.ts +22 -0
  25. package/dist/bull/bull-config.module.test.d.ts +1 -0
  26. package/dist/bull/index.d.ts +1 -0
  27. package/dist/config/load-framework-config.d.ts +32 -0
  28. package/dist/config/load-framework-config.test.d.ts +1 -0
  29. package/dist/database/prisma-connection.d.ts +48 -0
  30. package/dist/database/prisma-connection.test.d.ts +1 -0
  31. package/dist/email-rate-limit/email-rate-limit.decorator.d.ts +8 -0
  32. package/dist/email-rate-limit/email-rate-limit.decorator.test.d.ts +1 -0
  33. package/dist/email-rate-limit/email-rate-limit.guard.d.ts +11 -0
  34. package/dist/email-rate-limit/email-rate-limit.guard.test.d.ts +1 -0
  35. package/dist/email-rate-limit/email-rate-limit.module.d.ts +2 -0
  36. package/dist/health/health.controller.d.ts +11 -0
  37. package/dist/health/health.controller.test.d.ts +1 -0
  38. package/dist/health/health.interface.d.ts +31 -0
  39. package/dist/health/health.module.d.ts +5 -0
  40. package/dist/health/health.service.d.ts +12 -0
  41. package/dist/health/health.service.test.d.ts +1 -0
  42. package/dist/health/index.d.ts +6 -0
  43. package/dist/health/indicators/memory.indicator.d.ts +7 -0
  44. package/dist/health/indicators/memory.indicator.test.d.ts +1 -0
  45. package/dist/health/indicators/redis.indicator.d.ts +7 -0
  46. package/dist/health/indicators/redis.indicator.test.d.ts +1 -0
  47. package/dist/index.d.ts +40 -0
  48. package/dist/index.js +9 -0
  49. package/dist/index.mjs +9 -0
  50. package/dist/logging/index.d.ts +6 -0
  51. package/dist/logging/logger.interface.d.ts +29 -0
  52. package/dist/logging/logger.module.d.ts +14 -0
  53. package/dist/logging/logger.service.d.ts +31 -0
  54. package/dist/logging/logger.service.test.d.ts +1 -0
  55. package/dist/logging/logging.interceptor.d.ts +8 -0
  56. package/dist/logging/logging.interceptor.test.d.ts +1 -0
  57. package/dist/metrics/index.d.ts +5 -0
  58. package/dist/metrics/metrics.controller.d.ts +7 -0
  59. package/dist/metrics/metrics.controller.test.d.ts +1 -0
  60. package/dist/metrics/metrics.interceptor.d.ts +9 -0
  61. package/dist/metrics/metrics.interceptor.test.d.ts +1 -0
  62. package/dist/metrics/metrics.interface.d.ts +17 -0
  63. package/dist/metrics/metrics.module.d.ts +5 -0
  64. package/dist/metrics/metrics.service.d.ts +79 -0
  65. package/dist/metrics/metrics.service.test.d.ts +1 -0
  66. package/dist/notifications/index.d.ts +15 -0
  67. package/dist/notifications/interfaces/email-options.interface.d.ts +23 -0
  68. package/dist/notifications/interfaces/index.d.ts +6 -0
  69. package/dist/notifications/interfaces/push-options.interface.d.ts +16 -0
  70. package/dist/notifications/interfaces/sms-options.interface.d.ts +12 -0
  71. package/dist/notifications/notification.module.d.ts +2 -0
  72. package/dist/notifications/notification.module.test.d.ts +1 -0
  73. package/dist/notifications/notification.service.d.ts +28 -0
  74. package/dist/notifications/notification.service.test.d.ts +1 -0
  75. package/dist/notifications/providers/email/console.provider.d.ts +9 -0
  76. package/dist/notifications/providers/email/console.provider.test.d.ts +1 -0
  77. package/dist/notifications/providers/email/resend.provider.d.ts +24 -0
  78. package/dist/notifications/providers/email/resend.provider.test.d.ts +1 -0
  79. package/dist/notifications/providers/email-provider.interface.d.ts +17 -0
  80. package/dist/observability/index.d.ts +2 -0
  81. package/dist/observability/observability.interface.d.ts +32 -0
  82. package/dist/observability/observability.module.d.ts +24 -0
  83. package/dist/observability/observability.module.test.d.ts +1 -0
  84. package/dist/open-api-docs/create-swagger-document.d.ts +10 -0
  85. package/dist/open-api-docs/create-swagger-document.test.d.ts +1 -0
  86. package/dist/open-api-docs/generate-swagger-docs.d.ts +12 -0
  87. package/dist/open-api-docs/generate-swagger-docs.test.d.ts +1 -0
  88. package/dist/rate-limit/rate-limit-headers.interceptor.d.ts +5 -0
  89. package/dist/rate-limit/rate-limit-headers.interceptor.test.d.ts +1 -0
  90. package/dist/rate-limit/rate-limit.decorator.d.ts +11 -0
  91. package/dist/rate-limit/rate-limit.decorator.test.d.ts +1 -0
  92. package/dist/rate-limit/rate-limit.guard.d.ts +13 -0
  93. package/dist/rate-limit/rate-limit.guard.test.d.ts +1 -0
  94. package/dist/rate-limit/rate-limit.module.d.ts +2 -0
  95. package/dist/redis/redis.module.d.ts +2 -0
  96. package/dist/redis/redis.service.d.ts +17 -0
  97. package/dist/redis/redis.service.test.d.ts +1 -0
  98. package/dist/scheduler/index.d.ts +1 -0
  99. package/dist/scheduler/scheduler.guard.d.ts +73 -0
  100. package/dist/scheduler/scheduler.guard.test.d.ts +1 -0
  101. package/dist/secrets/index.d.ts +10 -0
  102. package/dist/secrets/providers/aws.provider.d.ts +56 -0
  103. package/dist/secrets/providers/aws.provider.test.d.ts +1 -0
  104. package/dist/secrets/providers/azure.provider.d.ts +70 -0
  105. package/dist/secrets/providers/azure.provider.test.d.ts +1 -0
  106. package/dist/secrets/providers/cloud-provider-adapter.d.ts +50 -0
  107. package/dist/secrets/providers/cloud-provider-adapter.test.d.ts +1 -0
  108. package/dist/secrets/providers/cloud-provider.interface.d.ts +86 -0
  109. package/dist/secrets/providers/gcp.provider.d.ts +64 -0
  110. package/dist/secrets/providers/gcp.provider.test.d.ts +1 -0
  111. package/dist/secrets/providers/local.provider.d.ts +82 -0
  112. package/dist/secrets/providers/local.provider.test.d.ts +1 -0
  113. package/dist/secrets/providers/provider-factory.d.ts +39 -0
  114. package/dist/secrets/providers/provider-factory.test.d.ts +1 -0
  115. package/dist/secrets/secrets.interface.d.ts +93 -0
  116. package/dist/secrets/secrets.module.d.ts +24 -0
  117. package/dist/secrets/secrets.service.d.ts +70 -0
  118. package/dist/secrets/secrets.service.test.d.ts +1 -0
  119. package/dist/service-client/base-service-client.d.ts +113 -0
  120. package/dist/service-client/base-service-client.test.d.ts +1 -0
  121. package/dist/service-client/filter-forward-headers.d.ts +11 -0
  122. package/dist/service-client/filter-forward-headers.test.d.ts +1 -0
  123. package/dist/telemetry/index.d.ts +4 -0
  124. package/dist/telemetry/telemetry.interface.d.ts +33 -0
  125. package/dist/telemetry/telemetry.module.d.ts +5 -0
  126. package/dist/telemetry/telemetry.service.d.ts +39 -0
  127. package/dist/telemetry/telemetry.service.test.d.ts +1 -0
  128. package/dist/telemetry/tracing.interceptor.d.ts +11 -0
  129. package/dist/telemetry/tracing.interceptor.test.d.ts +1 -0
  130. package/dist/utils/package-json.d.ts +25 -0
  131. package/package.json +102 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 tsdevstack
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # @tsdevstack/nest-common
2
+
3
+ Shared NestJS modules for tsdevstack microservices. Provides auth, rate limiting, secrets management, observability, notifications, database connectivity, and application bootstrap — so every service starts with production-ready infrastructure.
4
+
5
+ ## Features
6
+
7
+ - **Authentication** — Kong JWT validation guard with public/partner route decorators
8
+ - **Rate Limiting** — Redis-backed rate limiting with per-route configuration
9
+ - **Email Rate Limiting** — Dedicated rate limiter for email-sending endpoints
10
+ - **Secrets Management** — Multi-provider secrets (GCP Secret Manager, AWS Secrets Manager, Azure Key Vault)
11
+ - **Observability** — Logging (Pino), metrics (Prometheus/OpenTelemetry), tracing (OTLP), health checks
12
+ - **Database** — Prisma connection pooling with `pg` adapter and SSL support
13
+ - **Notifications** — Email (Resend), SMS, and push notification service
14
+ - **Background Jobs** — BullMQ configuration and scheduler guard
15
+ - **Service Client** — Type-safe HTTP client for inter-service communication
16
+ - **Bootstrap** — `startApp()` and `startWorker()` for consistent app initialization
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install @tsdevstack/nest-common
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### Bootstrap a service
27
+
28
+ ```typescript
29
+ import { startApp } from '@tsdevstack/nest-common';
30
+ import { AppModule } from './app.module';
31
+
32
+ startApp(AppModule, {
33
+ serviceName: 'my-service',
34
+ port: 3000,
35
+ });
36
+ ```
37
+
38
+ ### Import modules
39
+
40
+ ```typescript
41
+ import {
42
+ AuthModule,
43
+ RedisModule,
44
+ RateLimitModule,
45
+ ObservabilityModule,
46
+ SecretsModule,
47
+ } from '@tsdevstack/nest-common';
48
+
49
+ @Module({
50
+ imports: [
51
+ ObservabilityModule.register({ serviceName: 'my-service' }),
52
+ SecretsModule,
53
+ AuthModule,
54
+ RedisModule,
55
+ RateLimitModule,
56
+ ],
57
+ })
58
+ export class AppModule {}
59
+ ```
60
+
61
+ ### Protect routes
62
+
63
+ ```typescript
64
+ import { AuthGuard, Public, RateLimit } from '@tsdevstack/nest-common';
65
+
66
+ @Controller('users')
67
+ @UseGuards(AuthGuard)
68
+ export class UsersController {
69
+ @Public()
70
+ @Get('health')
71
+ health() {
72
+ return { status: 'ok' };
73
+ }
74
+
75
+ @RateLimit({ points: 10, duration: 60 })
76
+ @Get('profile')
77
+ getProfile(@Req() req: AuthenticatedRequest) {
78
+ return req.user;
79
+ }
80
+ }
81
+ ```
82
+
83
+ ## Modules
84
+
85
+ | Module | Description |
86
+ |--------|-------------|
87
+ | `AuthModule` | Kong JWT validation, `@Public()` and `@PartnerApi()` decorators |
88
+ | `RedisModule` | Redis connection with retry and health checks |
89
+ | `RateLimitModule` | Redis-backed rate limiting with `@RateLimit()` decorator |
90
+ | `EmailRateLimitModule` | Dedicated email rate limiting |
91
+ | `SecretsModule` | Multi-cloud secrets loading (GCP, AWS, Azure) |
92
+ | `ObservabilityModule` | Logging, metrics, tracing, and health endpoints |
93
+ | `NotificationModule` | Email (Resend), SMS, and push notifications |
94
+ | `BullConfigModule` | BullMQ queue configuration |
95
+
96
+ ## Utilities
97
+
98
+ | Export | Description |
99
+ |--------|-------------|
100
+ | `startApp()` | Bootstrap a NestJS application with standard middleware |
101
+ | `startWorker()` | Bootstrap a background worker process |
102
+ | `createPrismaConnection()` | Prisma client with `pg` adapter and SSL |
103
+ | `BaseServiceClient` | HTTP client for service-to-service calls |
104
+ | `filterForwardHeaders()` | Header filtering for inter-service requests |
105
+ | `generateSwaggerDocs()` | OpenAPI documentation setup |
106
+ | `LoggerService` | Pino-based structured logging |
107
+ | `MetricsService` | Custom Prometheus metrics |
108
+
109
+ ## License
110
+
111
+ MIT
@@ -0,0 +1,62 @@
1
+ import { Request } from 'express';
2
+ /**
3
+ * User object extracted from Kong headers.
4
+ *
5
+ * Kong forwards JWT claims as `X-JWT-Claim-*` headers, which are
6
+ * dynamically extracted into this object. The `id` field is always
7
+ * present (from `X-Consumer-ID`), but all other fields are dynamic
8
+ * based on JWT claims.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // Kong headers:
13
+ * // X-Consumer-ID: user-123
14
+ * // X-JWT-Claim-Email: user@example.com
15
+ * // X-JWT-Claim-Roles: USER,ADMIN
16
+ * // X-JWT-Claim-TenantId: tenant-456
17
+ *
18
+ * // Resulting KongUser:
19
+ * {
20
+ * id: "user-123",
21
+ * email: "user@example.com",
22
+ * roles: ["USER", "ADMIN"],
23
+ * tenantId: "tenant-456"
24
+ * }
25
+ * ```
26
+ */
27
+ export interface KongUser {
28
+ /** User ID from X-Consumer-ID (JWT sub claim) */
29
+ id: string;
30
+ /** Dynamic claims extracted from X-JWT-Claim-* headers */
31
+ [key: string]: string | string[] | number | boolean | undefined;
32
+ }
33
+ /**
34
+ * Express Request with Kong authentication populated.
35
+ *
36
+ * After KongAuthGuard processes the request, either `user` (JWT auth)
37
+ * or `service` (API key auth) will be populated.
38
+ */
39
+ export interface AuthenticatedRequest extends Request {
40
+ /** User object (JWT authentication) */
41
+ user?: KongUser;
42
+ /** Service name (API key authentication) */
43
+ service?: string;
44
+ }
45
+ /**
46
+ * Kong header names for type safety.
47
+ *
48
+ * These are the standard headers that Kong sets after validating
49
+ * JWT tokens or API keys.
50
+ */
51
+ export declare enum KongHeaders {
52
+ /** Consumer ID (JWT sub claim) */
53
+ CONSUMER_ID = "x-consumer-id",
54
+ /** Consumer username (API key service name) */
55
+ CONSUMER_USERNAME = "x-consumer-username",
56
+ /** Credential identifier (JWT sub claim from kong-oidc-v3) */
57
+ CREDENTIAL_IDENTIFIER = "x-credential-identifier",
58
+ /** JWT claims as JSON (kong-oidc-v3 plugin) */
59
+ USERINFO = "x-userinfo",
60
+ /** Prefix for JWT claim headers (legacy) */
61
+ JWT_CLAIM_PREFIX = "x-jwt-claim-"
62
+ }
@@ -0,0 +1,181 @@
1
+ import { CanActivate, ExecutionContext } from '@nestjs/common';
2
+ import { Reflector } from '@nestjs/core';
3
+ import { SecretsService } from '../secrets/secrets.service';
4
+ /**
5
+ * Guard that validates requests came through Kong gateway and extracts user data.
6
+ *
7
+ * This guard implements the tsdevstack authentication architecture where:
8
+ * 1. Kong validates JWT signatures using JWKS endpoint
9
+ * 2. Kong forwards ALL JWT claims as JSON in `X-Userinfo` header (kong-oidc-v3)
10
+ * 3. Kong adds `X-Kong-Trust` header to prove requests came through gateway
11
+ * 4. Services validate Kong trust header for defense-in-depth security
12
+ * 5. Services trust Kong headers (network isolation + trust header prevents spoofing)
13
+ * 6. Services never validate JWT tokens themselves
14
+ *
15
+ * ## How It Works
16
+ *
17
+ * ### Kong Trust Header Verification
18
+ * - Kong adds `X-Kong-Trust` header with KONG_TRUST_TOKEN value to ALL requests
19
+ * - Guard verifies this header before processing authentication
20
+ * - Direct service-to-service calls with `x-api-key` bypass this check
21
+ * - Prevents direct access to backend services bypassing Kong
22
+ *
23
+ * ### JWT Authentication (User Requests)
24
+ * - Kong validates JWT and sets `X-Consumer-ID` (from JWT `sub` claim)
25
+ * - Kong forwards all JWT claims as JSON in `X-Userinfo` header
26
+ * - Guard parses the JSON and extracts ALL claims into `req.user` object
27
+ * - Claims preserve their original types (arrays, numbers, booleans, strings)
28
+ * - Falls back to legacy `X-JWT-Claim-*` headers for backward compatibility
29
+ *
30
+ * ### API Key Authentication (Service-to-Service)
31
+ * - Kong validates API key and sets `X-Consumer-Username` (service name)
32
+ * - Guard sets `req.service` to the service name
33
+ * - No user object is created
34
+ *
35
+ * ### Public Endpoints
36
+ * - Routes marked with `@Public()` decorator skip user authentication
37
+ * - But still require Kong trust header (unless direct service-to-service)
38
+ *
39
+ * @example Basic usage with JWT
40
+ * ```typescript
41
+ * @Controller('offers')
42
+ * export class OffersController {
43
+ * @Post()
44
+ * @UseGuards(AuthGuard)
45
+ * create(@Request() req: AuthenticatedRequest) {
46
+ * const { id, email, roles } = req.user;
47
+ * // Access any custom claims dynamically
48
+ * const tenantId = req.user.tenantId;
49
+ * }
50
+ * }
51
+ * ```
52
+ *
53
+ * @example Public endpoint
54
+ * ```typescript
55
+ * @Get()
56
+ * @Public()
57
+ * list() {
58
+ * // No user authentication required, but must come through Kong
59
+ * }
60
+ * ```
61
+ *
62
+ * @example Service-to-service with API key
63
+ * ```typescript
64
+ * @Get('internal')
65
+ * @UseGuards(AuthGuard)
66
+ * internal(@Request() req: AuthenticatedRequest) {
67
+ * const serviceName = req.service; // e.g., "bff-service"
68
+ * }
69
+ * ```
70
+ */
71
+ export declare class AuthGuard implements CanActivate {
72
+ private reflector;
73
+ private secrets;
74
+ private readonly logger;
75
+ constructor(reflector: Reflector, secrets: SecretsService);
76
+ /**
77
+ * Validates the request came through Kong and extracts authentication data.
78
+ *
79
+ * @param context - Execution context
80
+ * @returns true if authentication is valid or endpoint is public
81
+ * @throws UnauthorizedException if Kong headers are missing
82
+ */
83
+ canActivate(context: ExecutionContext): Promise<boolean>;
84
+ /**
85
+ * Extracts user object from Kong headers.
86
+ *
87
+ * kong-oidc-v3 forwards JWT claims as base64-encoded JSON in the `X-Userinfo` header.
88
+ * Falls back to legacy `X-JWT-Claim-*` headers for backward compatibility.
89
+ *
90
+ * @param headers - HTTP headers from the request
91
+ * @returns User object with id and all dynamic claims
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * // Input headers (kong-oidc-v3):
96
+ * {
97
+ * 'x-credential-identifier': 'user-123',
98
+ * 'x-userinfo': 'eyJzdWIiOiJ1c2VyLTEyMyIsImVtYWlsIjoidXNlckBleGFtcGxlLmNvbSIsInJvbGVzIjpbIlVTRVIiLCJBRE1JTiJdLCJ0ZW5hbnRJZCI6InRlbmFudC00NTYifQ=='
99
+ * }
100
+ *
101
+ * // Output user object:
102
+ * {
103
+ * id: 'user-123',
104
+ * email: 'user@example.com',
105
+ * roles: ['USER', 'ADMIN'],
106
+ * tenantId: 'tenant-456'
107
+ * }
108
+ * ```
109
+ */
110
+ private extractUserFromHeaders;
111
+ /**
112
+ * Converts kebab-case to camelCase.
113
+ *
114
+ * @param str - Kebab-case string (e.g., "tenant-id")
115
+ * @returns CamelCase string (e.g., "tenantId")
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * toCamelCase('tenant-id') // 'tenantId'
120
+ * toCamelCase('is-verified') // 'isVerified'
121
+ * toCamelCase('email') // 'email'
122
+ * ```
123
+ */
124
+ private toCamelCase;
125
+ /**
126
+ * Parses header value to appropriate JavaScript type.
127
+ *
128
+ * Kong forwards all JWT claims as strings. This method intelligently
129
+ * parses them back to their original types:
130
+ * - Arrays: "USER,ADMIN" → ["USER", "ADMIN"]
131
+ * - Numbers: "123" → 123
132
+ * - Booleans: "true" → true, "false" → false
133
+ * - Strings: everything else
134
+ *
135
+ * @param value - String value from header
136
+ * @returns Parsed value in appropriate type
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * parseValue('USER,ADMIN') // ['USER', 'ADMIN']
141
+ * parseValue('123') // 123
142
+ * parseValue('true') // true
143
+ * parseValue('false') // false
144
+ * parseValue('john@example.com') // 'john@example.com'
145
+ * ```
146
+ */
147
+ private parseValue;
148
+ /**
149
+ * Verifies that the request came through Kong gateway by validating the trust header.
150
+ * This is a defense-in-depth measure to prevent direct access to backend services.
151
+ *
152
+ * @param request - HTTP request object
153
+ * @throws UnauthorizedException if Kong trust header is missing or invalid
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * // Kong adds this header to all requests:
158
+ * // Request headers: { 'x-kong-trust': 'KONG_TRUST_TOKEN_VALUE' }
159
+ * // Service validates it matches the KONG_TRUST_TOKEN from secrets
160
+ * ```
161
+ */
162
+ private verifyKongTrustHeader;
163
+ /**
164
+ * Validates direct service-to-service API key authentication.
165
+ * Used when services call each other directly (bypassing Kong).
166
+ *
167
+ * @param request - HTTP request object
168
+ * @param apiKey - API key from x-api-key header
169
+ * @returns true if API key is valid
170
+ * @throws UnauthorizedException if API key configuration is missing
171
+ * @throws ForbiddenException if API key is invalid
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * // Service A calling Service B:
176
+ * // Request headers: { 'x-api-key': 'AUTH_SERVICE_API_KEY_VALUE' }
177
+ * // Service B validates against its own API_KEY from secrets
178
+ * ```
179
+ */
180
+ private validateServiceApiKey;
181
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Kong Authentication Module.
3
+ *
4
+ * Provides the AuthGuard globally to all modules in the application.
5
+ * Import this module once in your root AppModule to make AuthGuard
6
+ * available throughout your application.
7
+ *
8
+ * ## Features
9
+ * - Dynamic JWT claim extraction from Kong headers
10
+ * - Service-to-service API key authentication
11
+ * - @Public() decorator for public endpoints
12
+ * - Network isolation security (trusts Kong headers only)
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // app.module.ts
17
+ * @Module({
18
+ * imports: [
19
+ * AuthModule,
20
+ * // ... other modules
21
+ * ],
22
+ * })
23
+ * export class AppModule {}
24
+ * ```
25
+ *
26
+ * @example Usage in controllers
27
+ * ```typescript
28
+ * @Controller('offers')
29
+ * export class OffersController {
30
+ * @Get()
31
+ * @Public()
32
+ * list() {
33
+ * // Public endpoint
34
+ * }
35
+ *
36
+ * @Post()
37
+ * @UseGuards(AuthGuard)
38
+ * create(@Request() req: AuthenticatedRequest) {
39
+ * const { id, email, roles } = req.user;
40
+ * }
41
+ * }
42
+ * ```
43
+ */
44
+ export declare class AuthModule {
45
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Authentication Module
3
+ *
4
+ * Provides authentication for tsdevstack applications including:
5
+ * - Kong gateway JWT authentication
6
+ * - Kong API key authentication
7
+ * - Direct service-to-service API key authentication
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ export { AuthModule } from './auth.module';
12
+ export { AuthGuard } from './auth.guard';
13
+ export { Public, IS_PUBLIC_KEY } from './public.decorator';
14
+ export { PartnerApi, IS_PARTNER_API_KEY } from './partner-api.decorator';
15
+ export { Partner } from './partner.decorator';
16
+ export type { KongUser, AuthenticatedRequest } from './auth-user.interface';
17
+ export { KongHeaders } from './auth-user.interface';
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Metadata key for the @PartnerApi() decorator.
3
+ */
4
+ export declare const IS_PARTNER_API_KEY = "isPartnerApi";
5
+ /**
6
+ * Decorator to mark routes as accessible via Partner API (requires API key).
7
+ *
8
+ * Routes marked with this decorator will be exposed under the /api prefix
9
+ * in Kong Gateway and require a valid API key for access.
10
+ *
11
+ * This decorator is ADDITIVE, not exclusive:
12
+ * - Can be used alone for partner-only access
13
+ * - Can be combined with @ApiBearerAuth() for dual access (JWT + Partner API)
14
+ *
15
+ * @example Partner-only endpoint
16
+ * ```typescript
17
+ * @Controller('offers')
18
+ * export class OffersController {
19
+ * @Get('current-plan')
20
+ * @PartnerApi()
21
+ * getCurrentPlan() {
22
+ * // Accessible only via /api/offers/current-plan with API key
23
+ * }
24
+ * }
25
+ * ```
26
+ *
27
+ * @example Dual-access endpoint (JWT + Partner API)
28
+ * ```typescript
29
+ * @Controller('data')
30
+ * export class DataController {
31
+ * @Get('export')
32
+ * @ApiBearerAuth()
33
+ * @PartnerApi()
34
+ * exportData() {
35
+ * // Accessible via:
36
+ * // - /data/export with JWT token (for users)
37
+ * // - /api/data/export with API key (for partners)
38
+ * }
39
+ * }
40
+ * ```
41
+ */
42
+ export declare const PartnerApi: () => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Extracts partner identifier from Kong's X-Consumer-Username header.
3
+ *
4
+ * Kong automatically adds this header when a valid API key is used.
5
+ * The value is the partner's username as defined in .secrets.user.json.
6
+ *
7
+ * @returns Partner username string, or undefined if not present
8
+ *
9
+ * @example Basic usage
10
+ * ```typescript
11
+ * @Controller('webhooks')
12
+ * export class WebhooksController {
13
+ * @PartnerApi()
14
+ * @Post('data')
15
+ * async receiveData(@Partner() partner: string) {
16
+ * // partner = "acme-corp" (from X-Consumer-Username header)
17
+ * this.logger.info('Partner API call', { partner });
18
+ * return this.processData();
19
+ * }
20
+ * }
21
+ * ```
22
+ *
23
+ * @example With optional typing (dual JWT + Partner access)
24
+ * ```typescript
25
+ * @Controller('exports')
26
+ * export class ExportsController {
27
+ * @ApiBearerAuth()
28
+ * @PartnerApi()
29
+ * @Get('data')
30
+ * async exportData(
31
+ * @User() user?: AuthUser,
32
+ * @Partner() partner?: string,
33
+ * ) {
34
+ * if (partner) {
35
+ * // Called via /api/exports/data with API key
36
+ * this.logger.info('Partner export', { partner });
37
+ * } else if (user) {
38
+ * // Called via /exports/data with JWT
39
+ * this.logger.info('User export', { userId: user.id });
40
+ * }
41
+ * return this.getExportData();
42
+ * }
43
+ * }
44
+ * ```
45
+ *
46
+ * @example With logging and tracking
47
+ * ```typescript
48
+ * @PartnerApi()
49
+ * @Post('webhook')
50
+ * async handleWebhook(
51
+ * @Partner() partner: string,
52
+ * @Body() data: WebhookDto,
53
+ * ) {
54
+ * await this.analytics.trackPartnerUsage(partner, '/webhook');
55
+ * await this.webhookService.process(partner, data);
56
+ * return { success: true };
57
+ * }
58
+ * ```
59
+ */
60
+ export declare const Partner: (...dataOrPipes: unknown[]) => ParameterDecorator;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Metadata key for the @Public() decorator.
3
+ */
4
+ export declare const IS_PUBLIC_KEY = "isPublic";
5
+ /**
6
+ * Decorator to mark routes as public (no authentication required).
7
+ *
8
+ * When applied to a controller method or class, KongAuthGuard will
9
+ * skip authentication checks for those routes.
10
+ *
11
+ * @example Method-level (specific endpoint is public)
12
+ * ```typescript
13
+ * @Controller('auth')
14
+ * export class AuthController {
15
+ * @Post('login')
16
+ * @Public()
17
+ * async login(@Body() dto: LoginDto) {
18
+ * // No authentication required for login
19
+ * }
20
+ *
21
+ * @Get('profile')
22
+ * @UseGuards(KongAuthGuard)
23
+ * async getProfile(@Request() req: AuthenticatedRequest) {
24
+ * // Authentication required
25
+ * const user = req.user;
26
+ * }
27
+ * }
28
+ * ```
29
+ *
30
+ * @example Class-level (all endpoints are public)
31
+ * ```typescript
32
+ * @Controller('health')
33
+ * @Public()
34
+ * export class HealthController {
35
+ * @Get()
36
+ * check() {
37
+ * return { status: 'ok' };
38
+ * }
39
+ * }
40
+ * ```
41
+ */
42
+ export declare const Public: () => import("@nestjs/common").CustomDecorator<string>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ import { KongUser } from '../auth-user.interface';
2
+ /**
3
+ * Extracts user object from Kong headers.
4
+ *
5
+ * Dynamically extracts ALL JWT claims from headers that start with
6
+ * `X-JWT-Claim-*`. This makes the authentication future-proof - any
7
+ * new claims added to the JWT will automatically flow through without
8
+ * code changes.
9
+ *
10
+ * @param headers - HTTP headers from the request
11
+ * @returns User object with id and all dynamic claims
12
+ *
13
+ * @example Basic extraction
14
+ * ```typescript
15
+ * const headers = {
16
+ * 'x-consumer-id': 'user-123',
17
+ * 'x-jwt-claim-email': 'user@example.com',
18
+ * 'x-jwt-claim-roles': 'USER,ADMIN',
19
+ * };
20
+ *
21
+ * extractUserFromHeaders(headers);
22
+ * // {
23
+ * // id: 'user-123',
24
+ * // email: 'user@example.com',
25
+ * // roles: ['USER', 'ADMIN']
26
+ * // }
27
+ * ```
28
+ *
29
+ * @example With camelCase conversion
30
+ * ```typescript
31
+ * const headers = {
32
+ * 'x-consumer-id': 'user-123',
33
+ * 'x-jwt-claim-tenant-id': 'tenant-456',
34
+ * 'x-jwt-claim-is-verified': 'true',
35
+ * };
36
+ *
37
+ * extractUserFromHeaders(headers);
38
+ * // {
39
+ * // id: 'user-123',
40
+ * // tenantId: 'tenant-456',
41
+ * // isVerified: true
42
+ * // }
43
+ * ```
44
+ */
45
+ export declare function extractUserFromHeaders(headers: Record<string, string>): KongUser;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Utility functions for Kong authentication.
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export { toCamelCase } from './to-camel-case';
7
+ export { parseHeaderValue } from './parse-header-value';
8
+ export { extractUserFromHeaders } from './extract-user-from-headers';