@nauth-toolkit/nestjs 0.1.13 → 0.1.17
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.
- package/dist/auth.module.d.ts +48 -0
- package/dist/auth.module.d.ts.map +1 -1
- package/dist/auth.module.js +161 -19
- package/dist/auth.module.js.map +1 -1
- package/dist/decorators/client-info.decorator.d.ts +39 -0
- package/dist/decorators/client-info.decorator.d.ts.map +1 -1
- package/dist/decorators/client-info.decorator.js +41 -0
- package/dist/decorators/client-info.decorator.js.map +1 -1
- package/dist/decorators/current-user.decorator.d.ts +6 -0
- package/dist/decorators/current-user.decorator.d.ts.map +1 -1
- package/dist/decorators/current-user.decorator.js +6 -0
- package/dist/decorators/current-user.decorator.js.map +1 -1
- package/dist/decorators/public.decorator.d.ts +7 -0
- package/dist/decorators/public.decorator.d.ts.map +1 -1
- package/dist/decorators/public.decorator.js +7 -0
- package/dist/decorators/public.decorator.js.map +1 -1
- package/dist/decorators/token-delivery.decorator.d.ts +20 -0
- package/dist/decorators/token-delivery.decorator.d.ts.map +1 -1
- package/dist/dto/index.d.ts +9 -0
- package/dist/dto/index.d.ts.map +1 -1
- package/dist/dto/index.js +10 -0
- package/dist/dto/index.js.map +1 -1
- package/dist/factories/storage-adapter.factory.d.ts +107 -0
- package/dist/factories/storage-adapter.factory.d.ts.map +1 -1
- package/dist/factories/storage-adapter.factory.js +129 -0
- package/dist/factories/storage-adapter.factory.js.map +1 -1
- package/dist/filters/nauth-http-exception.filter.d.ts +80 -0
- package/dist/filters/nauth-http-exception.filter.d.ts.map +1 -1
- package/dist/filters/nauth-http-exception.filter.js +96 -0
- package/dist/filters/nauth-http-exception.filter.js.map +1 -1
- package/dist/guards/auth.guard.d.ts +26 -0
- package/dist/guards/auth.guard.d.ts.map +1 -1
- package/dist/guards/auth.guard.js +44 -0
- package/dist/guards/auth.guard.js.map +1 -1
- package/dist/guards/csrf.guard.d.ts +21 -0
- package/dist/guards/csrf.guard.d.ts.map +1 -1
- package/dist/guards/csrf.guard.js +30 -1
- package/dist/guards/csrf.guard.js.map +1 -1
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -1
- package/dist/interceptors/client-info.interceptor.d.ts +37 -0
- package/dist/interceptors/client-info.interceptor.d.ts.map +1 -1
- package/dist/interceptors/client-info.interceptor.js +89 -1
- package/dist/interceptors/client-info.interceptor.js.map +1 -1
- package/dist/interceptors/cookie-token.interceptor.d.ts +16 -0
- package/dist/interceptors/cookie-token.interceptor.d.ts.map +1 -1
- package/dist/interceptors/cookie-token.interceptor.js +80 -16
- package/dist/interceptors/cookie-token.interceptor.js.map +1 -1
- package/dist/providers/nestjs-logger.adapter.d.ts +96 -0
- package/dist/providers/nestjs-logger.adapter.d.ts.map +1 -1
- package/dist/providers/nestjs-logger.adapter.js +105 -1
- package/dist/providers/nestjs-logger.adapter.js.map +1 -1
- package/dist/services/csrf.service.d.ts +61 -0
- package/dist/services/csrf.service.d.ts.map +1 -1
- package/dist/services/csrf.service.js +62 -1
- package/dist/services/csrf.service.js.map +1 -1
- package/dist/services/migrations-bootstrap.service.d.ts +6 -0
- package/dist/services/migrations-bootstrap.service.d.ts.map +1 -1
- package/dist/services/migrations-bootstrap.service.js +6 -0
- package/dist/services/migrations-bootstrap.service.js.map +1 -1
- package/package.json +14 -2
|
@@ -1,8 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Storage Adapter Factory Functions
|
|
4
|
+
*
|
|
5
|
+
* Provides clean factory functions for creating storage adapters.
|
|
6
|
+
* These factories handle proper initialization and simplify configuration.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createDatabaseStorageAdapter, createRedisStorageAdapter } from '@nauth-toolkit/nestjs';
|
|
11
|
+
*
|
|
12
|
+
* export const authConfig = {
|
|
13
|
+
* // Database adapter (uses existing TypeORM connection)
|
|
14
|
+
* storageAdapter: createDatabaseStorageAdapter(),
|
|
15
|
+
*
|
|
16
|
+
* // Or Redis adapter
|
|
17
|
+
* storageAdapter: createRedisStorageAdapter(process.env.REDIS_URL),
|
|
18
|
+
* };
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
2
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
22
|
exports.createDatabaseStorageAdapter = createDatabaseStorageAdapter;
|
|
4
23
|
exports.createRedisStorageAdapter = createRedisStorageAdapter;
|
|
5
24
|
exports.createRedisClusterAdapter = createRedisClusterAdapter;
|
|
25
|
+
/**
|
|
26
|
+
* Check whether an unknown error is a Node "MODULE_NOT_FOUND" for a specific module.
|
|
27
|
+
*
|
|
28
|
+
* We intentionally match by both error code and the module name inside the message to avoid
|
|
29
|
+
* incorrectly catching nested missing modules.
|
|
30
|
+
*
|
|
31
|
+
* @param error - Unknown caught error
|
|
32
|
+
* @param moduleName - The module name we expect to be missing (e.g. '@nauth-toolkit/storage-database')
|
|
33
|
+
* @returns True if this error represents "moduleName is not installed"
|
|
34
|
+
*/
|
|
6
35
|
function isModuleNotFoundFor(error, moduleName) {
|
|
7
36
|
if (!(error instanceof Error)) {
|
|
8
37
|
return false;
|
|
@@ -11,9 +40,37 @@ function isModuleNotFoundFor(error, moduleName) {
|
|
|
11
40
|
if (errno.code !== 'MODULE_NOT_FOUND') {
|
|
12
41
|
return false;
|
|
13
42
|
}
|
|
43
|
+
// Node error messages usually contain: "Cannot find module '<name>'"
|
|
14
44
|
return typeof error.message === 'string' && error.message.includes(`'${moduleName}'`);
|
|
15
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Create a database storage adapter
|
|
48
|
+
*
|
|
49
|
+
* Uses the existing TypeORM connection. Make sure storage entities are included
|
|
50
|
+
* in your TypeORM.forRoot() configuration:
|
|
51
|
+
*
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { getNAuthTransientStorageEntities } from '@nauth-toolkit/database-typeorm-postgres';
|
|
54
|
+
* TypeOrmModule.forRoot({
|
|
55
|
+
* entities: [...getNAuthEntities(), ...getNAuthTransientStorageEntities()],
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @returns DatabaseStorageAdapter instance
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* import { createDatabaseStorageAdapter } from '@nauth-toolkit/nestjs';
|
|
64
|
+
*
|
|
65
|
+
* export const authConfig = {
|
|
66
|
+
* storageAdapter: createDatabaseStorageAdapter(),
|
|
67
|
+
* // ... other config
|
|
68
|
+
* };
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
16
71
|
function createDatabaseStorageAdapter() {
|
|
72
|
+
// Lazy import to avoid bundling if not used.
|
|
73
|
+
// ⚠️ Note: This adapter lives in a separate package and must be installed by the consumer app.
|
|
17
74
|
let DatabaseStorageAdapterCtor;
|
|
18
75
|
try {
|
|
19
76
|
const mod = require('@nauth-toolkit/storage-database');
|
|
@@ -32,9 +89,45 @@ function createDatabaseStorageAdapter() {
|
|
|
32
89
|
}
|
|
33
90
|
throw error;
|
|
34
91
|
}
|
|
92
|
+
// Repositories are injected by AuthModule via setRepositories (when available).
|
|
35
93
|
return new DatabaseStorageAdapterCtor(null, null, null);
|
|
36
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a Redis storage adapter
|
|
97
|
+
*
|
|
98
|
+
* Creates and connects a Redis client automatically using the `redis` package (node-redis).
|
|
99
|
+
* The client connection is managed internally by the adapter.
|
|
100
|
+
*
|
|
101
|
+
* Supports both single-instance Redis and Redis Cluster configurations.
|
|
102
|
+
*
|
|
103
|
+
* @param url - Redis connection URL (default: 'redis://localhost:6379')
|
|
104
|
+
* Supports authentication in URL format:
|
|
105
|
+
* - redis://localhost:6379 (no auth)
|
|
106
|
+
* - redis://:password@localhost:6379 (password only)
|
|
107
|
+
* - redis://username:password@localhost:6379 (username + password)
|
|
108
|
+
* - rediss://localhost:6379 (TLS/SSL, with optional auth)
|
|
109
|
+
* @returns RedisStorageAdapter instance
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* import { createRedisStorageAdapter, createRedisClusterAdapter } from '@nauth-toolkit/nestjs';
|
|
114
|
+
*
|
|
115
|
+
* export const authConfig = {
|
|
116
|
+
* // Single-instance Redis
|
|
117
|
+
* storageAdapter: createRedisStorageAdapter(process.env.REDIS_URL),
|
|
118
|
+
*
|
|
119
|
+
* // Or Redis Cluster (for production high-availability)
|
|
120
|
+
* storageAdapter: createRedisClusterAdapter([
|
|
121
|
+
* { url: 'redis://redis-node-1:6379' },
|
|
122
|
+
* { url: 'redis://redis-node-2:6379' },
|
|
123
|
+
* { url: 'redis://redis-node-3:6379' },
|
|
124
|
+
* ]),
|
|
125
|
+
* };
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
37
128
|
function createRedisStorageAdapter(url = 'redis://localhost:6379') {
|
|
129
|
+
// Lazy import to avoid bundling if not used.
|
|
130
|
+
// ⚠️ Note: This adapter + the redis client are separate deps that must be installed by the consumer app.
|
|
38
131
|
let RedisStorageAdapterCtor;
|
|
39
132
|
try {
|
|
40
133
|
const mod = require('@nauth-toolkit/storage-redis');
|
|
@@ -72,9 +165,43 @@ function createRedisStorageAdapter(url = 'redis://localhost:6379') {
|
|
|
72
165
|
throw error;
|
|
73
166
|
}
|
|
74
167
|
const redisClient = createClientFn({ url });
|
|
168
|
+
// Don't connect here - let adapter.initialize() handle connection
|
|
169
|
+
// This ensures proper error handling and allows initialize() to wait for connection
|
|
75
170
|
return new RedisStorageAdapterCtor(redisClient);
|
|
76
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Create a Redis Cluster storage adapter
|
|
174
|
+
*
|
|
175
|
+
* Creates and connects a Redis Cluster client automatically using the `redis` package (node-redis).
|
|
176
|
+
* The cluster client handles automatic topology discovery, command routing, and failover.
|
|
177
|
+
*
|
|
178
|
+
* **Production Use:**
|
|
179
|
+
* Use Redis Cluster for high-availability production deployments. The cluster automatically:
|
|
180
|
+
* - Discovers cluster topology
|
|
181
|
+
* - Routes commands to correct nodes based on key hash slots
|
|
182
|
+
* - Handles node failures and redirects (MOVED/ASK errors)
|
|
183
|
+
* - Provides high availability and horizontal scaling
|
|
184
|
+
*
|
|
185
|
+
* @param nodes - Array of cluster node URLs
|
|
186
|
+
* @returns RedisStorageAdapter instance
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```typescript
|
|
190
|
+
* import { createRedisClusterAdapter } from '@nauth-toolkit/nestjs';
|
|
191
|
+
*
|
|
192
|
+
* export const authConfig = {
|
|
193
|
+
* // Redis Cluster with 3 nodes
|
|
194
|
+
* storageAdapter: createRedisClusterAdapter([
|
|
195
|
+
* { url: 'redis://redis-node-1:6379' },
|
|
196
|
+
* { url: 'redis://redis-node-2:6379' },
|
|
197
|
+
* { url: 'redis://redis-node-3:6379' },
|
|
198
|
+
* ]),
|
|
199
|
+
* };
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
77
202
|
function createRedisClusterAdapter(nodes) {
|
|
203
|
+
// Lazy import to avoid bundling if not used.
|
|
204
|
+
// ⚠️ Note: This adapter + the redis client are separate deps that must be installed by the consumer app.
|
|
78
205
|
let RedisStorageAdapterCtor;
|
|
79
206
|
try {
|
|
80
207
|
const mod = require('@nauth-toolkit/storage-redis');
|
|
@@ -114,6 +241,8 @@ function createRedisClusterAdapter(nodes) {
|
|
|
114
241
|
const clusterClient = createClusterFn({
|
|
115
242
|
rootNodes: nodes,
|
|
116
243
|
});
|
|
244
|
+
// Don't connect here - let adapter.initialize() handle connection
|
|
245
|
+
// This ensures proper error handling and allows initialize() to wait for connection
|
|
117
246
|
return new RedisStorageAdapterCtor(clusterClient);
|
|
118
247
|
}
|
|
119
248
|
//# sourceMappingURL=storage-adapter.factory.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-adapter.factory.js","sourceRoot":"","sources":["../../src/factories/storage-adapter.factory.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"storage-adapter.factory.js","sourceRoot":"","sources":["../../src/factories/storage-adapter.factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,87 @@
|
|
|
1
1
|
import { ExceptionFilter, ArgumentsHost } from '@nestjs/common';
|
|
2
2
|
import { NAuthException } from '@nauth-toolkit/core';
|
|
3
|
+
/**
|
|
4
|
+
* HTTP Exception Filter for NAuthException
|
|
5
|
+
*
|
|
6
|
+
* **Utility filter provided by nauth-toolkit** to properly map `NAuthException` domain exceptions
|
|
7
|
+
* to appropriate HTTP status codes and response formats.
|
|
8
|
+
*
|
|
9
|
+
* **Purpose:**
|
|
10
|
+
* This filter automatically converts `NAuthException` errors to HTTP responses with correct
|
|
11
|
+
* status codes using the `getHttpStatusForErrorCode()` helper function:
|
|
12
|
+
* - `AUTH_INVALID_CREDENTIALS` → 401 Unauthorized
|
|
13
|
+
* - `RATE_LIMIT_*` → 429 Too Many Requests
|
|
14
|
+
* - `VALIDATION_FAILED` → 400 Bad Request
|
|
15
|
+
* - `NOT_FOUND` → 404 Not Found
|
|
16
|
+
* - `INTERNAL_ERROR` → 500 Internal Server Error
|
|
17
|
+
* - etc.
|
|
18
|
+
*
|
|
19
|
+
* **Usage:**
|
|
20
|
+
* This filter is **recommended** for most applications as it ensures proper HTTP status codes.
|
|
21
|
+
* You can use it as-is, or extend it with custom logic (logging, monitoring, etc.).
|
|
22
|
+
*
|
|
23
|
+
* **Important:** This filter ONLY catches `NAuthException`. It will NOT interfere with
|
|
24
|
+
* your application's other exception filters or error handling.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* // Recommended: Use nauth-toolkit's filter for proper HTTP status codes
|
|
29
|
+
* import { NAuthHttpExceptionFilter } from '@nauth-toolkit/nestjs';
|
|
30
|
+
* app.useGlobalFilters(new NAuthHttpExceptionFilter());
|
|
31
|
+
*
|
|
32
|
+
* // Optional: Extend with custom logic
|
|
33
|
+
* @Catch(NAuthException)
|
|
34
|
+
* export class CustomNAuthFilter extends NAuthHttpExceptionFilter {
|
|
35
|
+
* catch(exception: NAuthException, host: ArgumentsHost) {
|
|
36
|
+
* // Add custom logging/monitoring
|
|
37
|
+
* this.logger.error('Auth error', exception);
|
|
38
|
+
* // Call parent for standard error handling
|
|
39
|
+
* super.catch(exception, host);
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* **Response format:**
|
|
45
|
+
* ```json
|
|
46
|
+
* {
|
|
47
|
+
* "statusCode": 429,
|
|
48
|
+
* "code": "RATE_LIMIT_SMS",
|
|
49
|
+
* "message": "Too many verification SMS sent",
|
|
50
|
+
* "details": {
|
|
51
|
+
* "retryAfter": 3600,
|
|
52
|
+
* "currentCount": 4
|
|
53
|
+
* },
|
|
54
|
+
* "timestamp": "2025-10-31T12:00:00.000Z",
|
|
55
|
+
* "path": "/auth/verify-phone"
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* **Customization:**
|
|
60
|
+
* If you need custom behavior, extend this class or create your own filter:
|
|
61
|
+
* ```typescript
|
|
62
|
+
* @Catch(NAuthException)
|
|
63
|
+
* export class CustomNAuthFilter extends NAuthHttpExceptionFilter {
|
|
64
|
+
* catch(exception: NAuthException, host: ArgumentsHost) {
|
|
65
|
+
* // Add additional logging
|
|
66
|
+
* this.logger.error(exception);
|
|
67
|
+
*
|
|
68
|
+
* // Call parent or implement custom logic
|
|
69
|
+
* super.catch(exception, host);
|
|
70
|
+
* }
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
3
74
|
export declare class NAuthHttpExceptionFilter implements ExceptionFilter<NAuthException> {
|
|
4
75
|
private readonly logger;
|
|
76
|
+
/**
|
|
77
|
+
* Catch and process NAuthException
|
|
78
|
+
*
|
|
79
|
+
* Converts the exception to an HTTP response with appropriate status code.
|
|
80
|
+
* Logs errors for debugging and monitoring.
|
|
81
|
+
*
|
|
82
|
+
* @param exception - The NAuthException instance
|
|
83
|
+
* @param host - ArgumentsHost for accessing request/response
|
|
84
|
+
*/
|
|
5
85
|
catch(exception: NAuthException, host: ArgumentsHost): void;
|
|
6
86
|
}
|
|
7
87
|
//# sourceMappingURL=nauth-http-exception.filter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nauth-http-exception.filter.d.ts","sourceRoot":"","sources":["../../src/filters/nauth-http-exception.filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAS,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAA6B,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"nauth-http-exception.filter.d.ts","sourceRoot":"","sources":["../../src/filters/nauth-http-exception.filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAS,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAA6B,MAAM,qBAAqB,CAAC;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,qBACa,wBAAyB,YAAW,eAAe,CAAC,cAAc,CAAC;IAC9E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IAEpE;;;;;;;;OAQG;IACH,KAAK,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;CAgG5D"}
|
|
@@ -10,13 +10,97 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.NAuthHttpExceptionFilter = void 0;
|
|
11
11
|
const common_1 = require("@nestjs/common");
|
|
12
12
|
const core_1 = require("@nauth-toolkit/core");
|
|
13
|
+
/**
|
|
14
|
+
* HTTP Exception Filter for NAuthException
|
|
15
|
+
*
|
|
16
|
+
* **Utility filter provided by nauth-toolkit** to properly map `NAuthException` domain exceptions
|
|
17
|
+
* to appropriate HTTP status codes and response formats.
|
|
18
|
+
*
|
|
19
|
+
* **Purpose:**
|
|
20
|
+
* This filter automatically converts `NAuthException` errors to HTTP responses with correct
|
|
21
|
+
* status codes using the `getHttpStatusForErrorCode()` helper function:
|
|
22
|
+
* - `AUTH_INVALID_CREDENTIALS` → 401 Unauthorized
|
|
23
|
+
* - `RATE_LIMIT_*` → 429 Too Many Requests
|
|
24
|
+
* - `VALIDATION_FAILED` → 400 Bad Request
|
|
25
|
+
* - `NOT_FOUND` → 404 Not Found
|
|
26
|
+
* - `INTERNAL_ERROR` → 500 Internal Server Error
|
|
27
|
+
* - etc.
|
|
28
|
+
*
|
|
29
|
+
* **Usage:**
|
|
30
|
+
* This filter is **recommended** for most applications as it ensures proper HTTP status codes.
|
|
31
|
+
* You can use it as-is, or extend it with custom logic (logging, monitoring, etc.).
|
|
32
|
+
*
|
|
33
|
+
* **Important:** This filter ONLY catches `NAuthException`. It will NOT interfere with
|
|
34
|
+
* your application's other exception filters or error handling.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // Recommended: Use nauth-toolkit's filter for proper HTTP status codes
|
|
39
|
+
* import { NAuthHttpExceptionFilter } from '@nauth-toolkit/nestjs';
|
|
40
|
+
* app.useGlobalFilters(new NAuthHttpExceptionFilter());
|
|
41
|
+
*
|
|
42
|
+
* // Optional: Extend with custom logic
|
|
43
|
+
* @Catch(NAuthException)
|
|
44
|
+
* export class CustomNAuthFilter extends NAuthHttpExceptionFilter {
|
|
45
|
+
* catch(exception: NAuthException, host: ArgumentsHost) {
|
|
46
|
+
* // Add custom logging/monitoring
|
|
47
|
+
* this.logger.error('Auth error', exception);
|
|
48
|
+
* // Call parent for standard error handling
|
|
49
|
+
* super.catch(exception, host);
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* **Response format:**
|
|
55
|
+
* ```json
|
|
56
|
+
* {
|
|
57
|
+
* "statusCode": 429,
|
|
58
|
+
* "code": "RATE_LIMIT_SMS",
|
|
59
|
+
* "message": "Too many verification SMS sent",
|
|
60
|
+
* "details": {
|
|
61
|
+
* "retryAfter": 3600,
|
|
62
|
+
* "currentCount": 4
|
|
63
|
+
* },
|
|
64
|
+
* "timestamp": "2025-10-31T12:00:00.000Z",
|
|
65
|
+
* "path": "/auth/verify-phone"
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* **Customization:**
|
|
70
|
+
* If you need custom behavior, extend this class or create your own filter:
|
|
71
|
+
* ```typescript
|
|
72
|
+
* @Catch(NAuthException)
|
|
73
|
+
* export class CustomNAuthFilter extends NAuthHttpExceptionFilter {
|
|
74
|
+
* catch(exception: NAuthException, host: ArgumentsHost) {
|
|
75
|
+
* // Add additional logging
|
|
76
|
+
* this.logger.error(exception);
|
|
77
|
+
*
|
|
78
|
+
* // Call parent or implement custom logic
|
|
79
|
+
* super.catch(exception, host);
|
|
80
|
+
* }
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
13
84
|
let NAuthHttpExceptionFilter = NAuthHttpExceptionFilter_1 = class NAuthHttpExceptionFilter {
|
|
14
85
|
logger = new common_1.Logger(NAuthHttpExceptionFilter_1.name);
|
|
86
|
+
/**
|
|
87
|
+
* Catch and process NAuthException
|
|
88
|
+
*
|
|
89
|
+
* Converts the exception to an HTTP response with appropriate status code.
|
|
90
|
+
* Logs errors for debugging and monitoring.
|
|
91
|
+
*
|
|
92
|
+
* @param exception - The NAuthException instance
|
|
93
|
+
* @param host - ArgumentsHost for accessing request/response
|
|
94
|
+
*/
|
|
15
95
|
catch(exception, host) {
|
|
16
96
|
const ctx = host.switchToHttp();
|
|
97
|
+
// Platform-agnostic: Use generic types that work with any HTTP adapter (Express, Fastify, etc.)
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
99
|
const response = ctx.getResponse();
|
|
18
100
|
const request = ctx.getRequest();
|
|
101
|
+
// Get HTTP status code from error code
|
|
19
102
|
const statusCode = (0, core_1.getHttpStatusForErrorCode)(exception.code);
|
|
103
|
+
// Build error response
|
|
20
104
|
const errorResponse = {
|
|
21
105
|
statusCode,
|
|
22
106
|
code: exception.code,
|
|
@@ -25,26 +109,36 @@ let NAuthHttpExceptionFilter = NAuthHttpExceptionFilter_1 = class NAuthHttpExcep
|
|
|
25
109
|
timestamp: exception.timestamp,
|
|
26
110
|
path: request.url || 'unknown',
|
|
27
111
|
};
|
|
112
|
+
// Log error for debugging and monitoring
|
|
113
|
+
// Use appropriate log level based on status code
|
|
28
114
|
if (statusCode >= 500) {
|
|
115
|
+
// Server errors - log as error with full details
|
|
29
116
|
this.logger.error(`[${exception.code}] ${exception.message} - Path: ${request.url || 'unknown'} - Method: ${request.method || 'unknown'}`, exception.stack, 'NAuthHttpExceptionFilter');
|
|
30
117
|
}
|
|
31
118
|
else if (statusCode >= 400) {
|
|
119
|
+
// Client errors - log as warn (less critical)
|
|
32
120
|
this.logger.warn(`[${exception.code}] ${exception.message} - Path: ${request.url || 'unknown'} - Method: ${request.method || 'unknown'}`, 'NAuthHttpExceptionFilter');
|
|
33
121
|
}
|
|
34
122
|
else {
|
|
123
|
+
// Other status codes - log as debug
|
|
35
124
|
this.logger.debug(`[${exception.code}] ${exception.message} - Path: ${request.url || 'unknown'}`, 'NAuthHttpExceptionFilter');
|
|
36
125
|
}
|
|
126
|
+
// Send response (platform-agnostic - works with Express, Fastify, etc.)
|
|
127
|
+
// Set status code first, then send JSON (avoid chaining for better compatibility)
|
|
37
128
|
try {
|
|
129
|
+
// Method 1: Express pattern - set status then json
|
|
38
130
|
if (response.status && typeof response.status === 'function' && typeof response.json === 'function') {
|
|
39
131
|
response.status(statusCode);
|
|
40
132
|
response.json(errorResponse);
|
|
41
133
|
return;
|
|
42
134
|
}
|
|
135
|
+
// Method 2: Fastify pattern - use code() method
|
|
43
136
|
if (response.code && typeof response.code === 'function' && typeof response.send === 'function') {
|
|
44
137
|
response.code(statusCode);
|
|
45
138
|
response.send(errorResponse);
|
|
46
139
|
return;
|
|
47
140
|
}
|
|
141
|
+
// Method 3: Direct statusCode property (Express/Fastify fallback)
|
|
48
142
|
if (typeof response.statusCode !== 'undefined') {
|
|
49
143
|
response.statusCode = statusCode;
|
|
50
144
|
}
|
|
@@ -56,6 +150,7 @@ let NAuthHttpExceptionFilter = NAuthHttpExceptionFilter_1 = class NAuthHttpExcep
|
|
|
56
150
|
response.send(errorResponse);
|
|
57
151
|
return;
|
|
58
152
|
}
|
|
153
|
+
// Method 4: Last resort - try to set status and send
|
|
59
154
|
if (response.status && typeof response.status === 'function') {
|
|
60
155
|
response.status(statusCode);
|
|
61
156
|
}
|
|
@@ -70,6 +165,7 @@ let NAuthHttpExceptionFilter = NAuthHttpExceptionFilter_1 = class NAuthHttpExcep
|
|
|
70
165
|
}
|
|
71
166
|
}
|
|
72
167
|
catch (error) {
|
|
168
|
+
// If all else fails, log the error but don't crash
|
|
73
169
|
this.logger.error(`Failed to send error response: ${error instanceof Error ? error.message : 'Unknown error'}`, error instanceof Error ? error.stack : undefined, 'NAuthHttpExceptionFilter');
|
|
74
170
|
}
|
|
75
171
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nauth-http-exception.filter.js","sourceRoot":"","sources":["../../src/filters/nauth-http-exception.filter.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAA+E;AAC/E,8CAAgF;
|
|
1
|
+
{"version":3,"file":"nauth-http-exception.filter.js","sourceRoot":"","sources":["../../src/filters/nauth-http-exception.filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,22 @@ import { Reflector } from '@nestjs/core';
|
|
|
3
3
|
import { Repository } from 'typeorm';
|
|
4
4
|
import { NAuthConfig, BaseUser } from '@nauth-toolkit/core';
|
|
5
5
|
import { JwtService, SessionService } from '@nauth-toolkit/core/internal';
|
|
6
|
+
/**
|
|
7
|
+
* Native Auth Guard (NO Passport dependency)
|
|
8
|
+
*
|
|
9
|
+
* Validates JWT tokens from Authorization header
|
|
10
|
+
* and attaches user to request. Supports API clients.
|
|
11
|
+
*
|
|
12
|
+
* Security Features:
|
|
13
|
+
* - JWT token validation with session-based revocation
|
|
14
|
+
* - Session expiration checking
|
|
15
|
+
* - Token reuse detection via session management
|
|
16
|
+
* - Automatic session activity updates
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Works with Authorization header (API clients)
|
|
20
|
+
* Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
21
|
+
*/
|
|
6
22
|
export declare class AuthGuard implements CanActivate {
|
|
7
23
|
private readonly reflector;
|
|
8
24
|
private readonly jwtService;
|
|
@@ -11,6 +27,16 @@ export declare class AuthGuard implements CanActivate {
|
|
|
11
27
|
private readonly config;
|
|
12
28
|
constructor(reflector: Reflector, jwtService: JwtService, sessionService: SessionService, userRepository: Repository<BaseUser>, config: NAuthConfig);
|
|
13
29
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* Extract JWT token from request with strict source validation based on configuration
|
|
32
|
+
*
|
|
33
|
+
* Security rules:
|
|
34
|
+
* - JSON mode: Only Authorization header (reject cookies if present)
|
|
35
|
+
* - Cookies mode: Only httpOnly cookies (reject Bearer header if present)
|
|
36
|
+
* - Hybrid mode: Cookies first (web), then Authorization header (mobile)
|
|
37
|
+
*
|
|
38
|
+
* @param request - HTTP request
|
|
39
|
+
*/
|
|
14
40
|
private extractToken;
|
|
15
41
|
}
|
|
16
42
|
//# sourceMappingURL=auth.guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.guard.d.ts","sourceRoot":"","sources":["../../src/guards/auth.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,WAAW,EAAE,gBAAgB,EAAU,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EACL,WAAW,EAIX,QAAQ,EAET,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.guard.d.ts","sourceRoot":"","sources":["../../src/guards/auth.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,WAAW,EAAE,gBAAgB,EAAU,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EACL,WAAW,EAIX,QAAQ,EAET,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAI1E;;;;;;;;;;;;;;;GAeG;AACH,qBACa,SAAU,YAAW,WAAW;IAEzC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBANN,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,EAE9B,cAAc,EAAE,UAAU,CAAC,QAAQ,CAAC,EAEpC,MAAM,EAAE,WAAW;IAGhC,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAoH9D;;;;;;;;;OASG;IACH,OAAO,CAAC,YAAY;CAwCrB"}
|
|
@@ -20,6 +20,22 @@ const core_2 = require("@nauth-toolkit/core");
|
|
|
20
20
|
const internal_1 = require("@nauth-toolkit/core/internal");
|
|
21
21
|
const public_decorator_1 = require("../decorators/public.decorator");
|
|
22
22
|
const token_delivery_decorator_1 = require("../decorators/token-delivery.decorator");
|
|
23
|
+
/**
|
|
24
|
+
* Native Auth Guard (NO Passport dependency)
|
|
25
|
+
*
|
|
26
|
+
* Validates JWT tokens from Authorization header
|
|
27
|
+
* and attaches user to request. Supports API clients.
|
|
28
|
+
*
|
|
29
|
+
* Security Features:
|
|
30
|
+
* - JWT token validation with session-based revocation
|
|
31
|
+
* - Session expiration checking
|
|
32
|
+
* - Token reuse detection via session management
|
|
33
|
+
* - Automatic session activity updates
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Works with Authorization header (API clients)
|
|
37
|
+
* Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
38
|
+
*/
|
|
23
39
|
let AuthGuard = class AuthGuard {
|
|
24
40
|
reflector;
|
|
25
41
|
jwtService;
|
|
@@ -34,6 +50,7 @@ let AuthGuard = class AuthGuard {
|
|
|
34
50
|
this.config = config;
|
|
35
51
|
}
|
|
36
52
|
async canActivate(context) {
|
|
53
|
+
// Check if route is public
|
|
37
54
|
const isPublic = this.reflector.getAllAndOverride(public_decorator_1.IS_PUBLIC_KEY, [
|
|
38
55
|
context.getHandler(),
|
|
39
56
|
context.getClass(),
|
|
@@ -42,26 +59,38 @@ let AuthGuard = class AuthGuard {
|
|
|
42
59
|
return true;
|
|
43
60
|
}
|
|
44
61
|
const request = context.switchToHttp().getRequest();
|
|
62
|
+
// Extract token according to configured delivery mode
|
|
45
63
|
const token = this.extractToken(context);
|
|
46
64
|
if (!token) {
|
|
47
65
|
throw new core_2.NAuthException(core_2.AuthErrorCode.TOKEN_INVALID, 'No token provided');
|
|
48
66
|
}
|
|
67
|
+
// Validate token
|
|
49
68
|
const validation = await this.jwtService.validateAccessToken(token);
|
|
50
69
|
if (!validation.valid) {
|
|
51
70
|
throw new core_2.NAuthException(core_2.AuthErrorCode.TOKEN_INVALID, validation.error || 'Invalid token');
|
|
52
71
|
}
|
|
72
|
+
// ============================================================================
|
|
73
|
+
// CRITICAL SECURITY FIX #3: Optimistic Locking for TOCTOU Prevention
|
|
74
|
+
// ============================================================================
|
|
75
|
+
// Check if session is revoked
|
|
53
76
|
const sessionId = validation.payload.sessionId;
|
|
54
77
|
const session = await this.sessionService.findByIdLight(sessionId);
|
|
55
78
|
if (!session) {
|
|
56
79
|
throw new core_2.NAuthException(core_2.AuthErrorCode.SESSION_NOT_FOUND, 'Session not found');
|
|
57
80
|
}
|
|
81
|
+
// Store initial version for optimistic locking check
|
|
58
82
|
const initialVersion = session.version;
|
|
59
83
|
if (session.isRevoked) {
|
|
60
84
|
throw new core_2.NAuthException(core_2.AuthErrorCode.TOKEN_REUSE_DETECTED, 'Session has been revoked');
|
|
61
85
|
}
|
|
86
|
+
// Check if session is expired
|
|
62
87
|
if (session.expiresAt < new Date()) {
|
|
63
88
|
throw new core_2.NAuthException(core_2.AuthErrorCode.SESSION_EXPIRED, 'Session has expired');
|
|
64
89
|
}
|
|
90
|
+
// Load user by sub (external identifier from JWT payload)
|
|
91
|
+
// Include all non-sensitive fields needed by endpoints (profile, MFA status, etc.)
|
|
92
|
+
// Excludes: passwordHash, passwordHistory, totpSecret, backupCodes (sensitive)
|
|
93
|
+
// TODO: SHIT Work. NEEDS TO BE FIXED.
|
|
65
94
|
const user = await this.userRepository.findOne({
|
|
66
95
|
select: [
|
|
67
96
|
'id',
|
|
@@ -103,14 +132,27 @@ let AuthGuard = class AuthGuard {
|
|
|
103
132
|
if (!user.isActive) {
|
|
104
133
|
throw new core_2.NAuthException(core_2.AuthErrorCode.ACCOUNT_INACTIVE, 'Account is not active');
|
|
105
134
|
}
|
|
135
|
+
// SECURITY CRITICAL: Re-check session hasn't been modified (optimistic locking)
|
|
136
|
+
// Prevents TOCTOU (Time-of-Check-Time-of-Use) vulnerabilities
|
|
106
137
|
const revalidated = await this.sessionService.findByIdLight(sessionId);
|
|
107
138
|
if (!revalidated || revalidated.version !== initialVersion || revalidated.isRevoked) {
|
|
108
139
|
throw new core_2.NAuthException(core_2.AuthErrorCode.TOKEN_INVALID, 'Session was modified during request - possible security breach');
|
|
109
140
|
}
|
|
141
|
+
// Attach user to request
|
|
110
142
|
request.user = user;
|
|
111
143
|
request.token = validation.payload;
|
|
112
144
|
return true;
|
|
113
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Extract JWT token from request with strict source validation based on configuration
|
|
148
|
+
*
|
|
149
|
+
* Security rules:
|
|
150
|
+
* - JSON mode: Only Authorization header (reject cookies if present)
|
|
151
|
+
* - Cookies mode: Only httpOnly cookies (reject Bearer header if present)
|
|
152
|
+
* - Hybrid mode: Cookies first (web), then Authorization header (mobile)
|
|
153
|
+
*
|
|
154
|
+
* @param request - HTTP request
|
|
155
|
+
*/
|
|
114
156
|
extractToken(context) {
|
|
115
157
|
const request = context.switchToHttp().getRequest();
|
|
116
158
|
const cfg = this.config.tokenDelivery;
|
|
@@ -119,6 +161,7 @@ let AuthGuard = class AuthGuard {
|
|
|
119
161
|
const headerToken = authHeader?.startsWith('Bearer ') ? authHeader.substring(7) : null;
|
|
120
162
|
const accessTokenCookieName = (0, core_2.getAccessTokenCookieName)(this.config);
|
|
121
163
|
const cookieToken = request.cookies?.[accessTokenCookieName];
|
|
164
|
+
// Resolve per-request delivery. Route override > hybrid policy > method fallback
|
|
122
165
|
const routeMode = this.reflector.get(token_delivery_decorator_1.TOKEN_DELIVERY_KEY, context.getHandler());
|
|
123
166
|
let effective = 'json';
|
|
124
167
|
if (routeMode) {
|
|
@@ -139,6 +182,7 @@ let AuthGuard = class AuthGuard {
|
|
|
139
182
|
}
|
|
140
183
|
return cookieToken || null;
|
|
141
184
|
}
|
|
185
|
+
// effective === 'json'
|
|
142
186
|
if (cookieToken && !headerToken) {
|
|
143
187
|
throw new core_2.NAuthException(core_2.AuthErrorCode.COOKIES_NOT_ALLOWED, 'Cookie tokens are not allowed in JSON-only path.');
|
|
144
188
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.guard.js","sourceRoot":"","sources":["../../src/guards/auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAmF;AACnF,uCAAyC;AACzC,qCAAqC;AACrC,8CAO6B;AAC7B,2DAA0E;AAC1E,qEAA+D;AAC/D,qFAA2F;
|
|
1
|
+
{"version":3,"file":"auth.guard.js","sourceRoot":"","sources":["../../src/guards/auth.guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,27 @@ import { CanActivate, ExecutionContext } from '@nestjs/common';
|
|
|
2
2
|
import { Reflector } from '@nestjs/core';
|
|
3
3
|
import { NAuthConfig } from '@nauth-toolkit/core';
|
|
4
4
|
import { CsrfService } from '../services/csrf.service';
|
|
5
|
+
/**
|
|
6
|
+
* CSRF Guard
|
|
7
|
+
*
|
|
8
|
+
* Validates CSRF tokens for state-changing requests when using cookie-based token delivery.
|
|
9
|
+
* CSRF protection prevents Cross-Site Request Forgery attacks.
|
|
10
|
+
*
|
|
11
|
+
* Security Rules:
|
|
12
|
+
* - Only enforces for cookie-based token delivery (cookies or hybrid with web origins)
|
|
13
|
+
* - Skips safe HTTP methods (GET, HEAD, OPTIONS)
|
|
14
|
+
* - Skips excluded paths from configuration
|
|
15
|
+
* - Validates CSRF token from header matches cookie value
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // Applied globally via AuthModule when tokenDelivery.method === 'cookies' or 'hybrid'
|
|
20
|
+
* // Or applied per-route:
|
|
21
|
+
* @UseGuards(CsrfGuard)
|
|
22
|
+
* @Post('sensitive-action')
|
|
23
|
+
* async sensitiveAction() { ... }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
5
26
|
export declare class CsrfGuard implements CanActivate {
|
|
6
27
|
private readonly config;
|
|
7
28
|
private readonly csrfService;
|