@lenne.tech/nest-server 11.10.0 → 11.10.2
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/core/modules/auth/guards/auth.guard.d.ts +2 -2
- package/dist/core/modules/auth/guards/auth.guard.js +68 -8
- package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
- package/dist/core/modules/auth/guards/roles.guard.d.ts +3 -4
- package/dist/core/modules/auth/guards/roles.guard.js +64 -159
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth-token.service.d.ts +21 -0
- package/dist/core/modules/better-auth/better-auth-token.service.js +153 -0
- package/dist/core/modules/better-auth/better-auth-token.service.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth.types.d.ts +13 -0
- package/dist/core/modules/better-auth/better-auth.types.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.module.d.ts +2 -0
- package/dist/core/modules/better-auth/core-better-auth.module.js +33 -4
- package/dist/core/modules/better-auth/core-better-auth.module.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.service.d.ts +1 -0
- package/dist/core/modules/better-auth/core-better-auth.service.js +4 -0
- package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -1
- package/dist/core/modules/better-auth/index.d.ts +1 -0
- package/dist/core/modules/better-auth/index.js +1 -0
- package/dist/core/modules/better-auth/index.js.map +1 -1
- package/dist/core.module.js +1 -0
- package/dist/core.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/core/modules/auth/guards/auth.guard.ts +136 -23
- package/src/core/modules/auth/guards/roles.guard.ts +119 -239
- package/src/core/modules/better-auth/better-auth-token.service.ts +241 -0
- package/src/core/modules/better-auth/better-auth.types.ts +37 -0
- package/src/core/modules/better-auth/core-better-auth.controller.ts +1 -1
- package/src/core/modules/better-auth/core-better-auth.module.ts +51 -4
- package/src/core/modules/better-auth/core-better-auth.resolver.ts +1 -1
- package/src/core/modules/better-auth/core-better-auth.service.ts +13 -0
- package/src/core/modules/better-auth/index.ts +1 -0
- package/src/core.module.ts +3 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ExecutionContext, ForbiddenException, Injectable, Logger, Optional, UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { ModuleRef, Reflector } from '@nestjs/core';
|
|
3
3
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
4
|
-
import { getConnectionToken } from '@nestjs/mongoose';
|
|
5
|
-
import { Connection, Types } from 'mongoose';
|
|
6
4
|
import { firstValueFrom, isObservable } from 'rxjs';
|
|
7
5
|
|
|
8
6
|
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
7
|
+
import { BetterAuthTokenService } from '../../better-auth/better-auth-token.service';
|
|
8
|
+
import { BetterAuthenticatedUser } from '../../better-auth/better-auth.types';
|
|
9
9
|
import { CoreBetterAuthService } from '../../better-auth/core-better-auth.service';
|
|
10
10
|
import { ErrorCode } from '../../error-code';
|
|
11
11
|
import { AuthGuardStrategy } from '../auth-guard-strategy.enum';
|
|
@@ -23,7 +23,7 @@ import { AuthGuard } from './auth.guard';
|
|
|
23
23
|
* MULTI-TOKEN SUPPORT:
|
|
24
24
|
* This guard supports multiple authentication token types:
|
|
25
25
|
* 1. Legacy JWT tokens (Passport JWT strategy)
|
|
26
|
-
* 2. BetterAuth JWT tokens (verified via
|
|
26
|
+
* 2. BetterAuth JWT tokens (verified via BetterAuthTokenService)
|
|
27
27
|
* 3. BetterAuth session tokens (verified via database lookup)
|
|
28
28
|
*
|
|
29
29
|
* When Passport JWT validation fails, the guard falls back to BetterAuth verification:
|
|
@@ -37,7 +37,7 @@ import { AuthGuard } from './auth.guard';
|
|
|
37
37
|
export class RolesGuard extends AuthGuard(AuthGuardStrategy.JWT) {
|
|
38
38
|
private readonly logger = new Logger(RolesGuard.name);
|
|
39
39
|
private betterAuthService: CoreBetterAuthService | null = null;
|
|
40
|
-
private
|
|
40
|
+
private tokenService: BetterAuthTokenService | null = null;
|
|
41
41
|
private servicesResolved = false;
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -51,7 +51,7 @@ export class RolesGuard extends AuthGuard(AuthGuardStrategy.JWT) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
|
-
* Lazily resolve BetterAuth
|
|
54
|
+
* Lazily resolve BetterAuth services
|
|
55
55
|
*/
|
|
56
56
|
private resolveServices(): void {
|
|
57
57
|
if (this.servicesResolved || !this.moduleRef) {
|
|
@@ -65,10 +65,9 @@ export class RolesGuard extends AuthGuard(AuthGuardStrategy.JWT) {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
try {
|
|
68
|
-
|
|
69
|
-
this.mongoConnection = this.moduleRef.get(getConnectionToken(), { strict: false });
|
|
68
|
+
this.tokenService = this.moduleRef.get(BetterAuthTokenService, { strict: false });
|
|
70
69
|
} catch {
|
|
71
|
-
//
|
|
70
|
+
// BetterAuthTokenService not available
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
this.servicesResolved = true;
|
|
@@ -78,291 +77,172 @@ export class RolesGuard extends AuthGuard(AuthGuardStrategy.JWT) {
|
|
|
78
77
|
* Override canActivate to add BetterAuth JWT fallback
|
|
79
78
|
*
|
|
80
79
|
* Flow:
|
|
81
|
-
* 1.
|
|
82
|
-
* 2.
|
|
83
|
-
* 3. If BetterAuth
|
|
80
|
+
* 1. Check if roles are required - if not, skip authentication entirely
|
|
81
|
+
* 2. Check if user is already authenticated via BetterAuth middleware
|
|
82
|
+
* 3. If BetterAuth is enabled, try BetterAuth token verification first
|
|
83
|
+
* 4. Otherwise, try Passport JWT authentication (Legacy JWT)
|
|
84
|
+
* 5. If Passport fails and BetterAuth is enabled, try BetterAuth as fallback
|
|
85
|
+
*
|
|
86
|
+
* This order ensures IAM-only setups work without requiring JWT strategy registration.
|
|
84
87
|
*/
|
|
85
88
|
override async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
86
|
-
//
|
|
87
|
-
this.
|
|
89
|
+
// Get roles FIRST to check if authentication is even needed
|
|
90
|
+
const reflectorRoles = this.reflector.getAll<string[][]>('roles', [context.getHandler(), context.getClass()]);
|
|
91
|
+
const roles: string[] = reflectorRoles[0]
|
|
92
|
+
? reflectorRoles[1]
|
|
93
|
+
? [...reflectorRoles[0], ...reflectorRoles[1]]
|
|
94
|
+
: reflectorRoles[0]
|
|
95
|
+
: reflectorRoles[1];
|
|
88
96
|
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
} catch (passportError) {
|
|
94
|
-
// Passport JWT validation failed - try BetterAuth token fallback (JWT or session)
|
|
95
|
-
if (!this.betterAuthService?.isEnabled()) {
|
|
96
|
-
// BetterAuth not available - rethrow original error
|
|
97
|
-
throw passportError;
|
|
98
|
-
}
|
|
97
|
+
// Check if locked - always deny
|
|
98
|
+
if (roles && roles.includes(RoleEnum.S_NO_ONE)) {
|
|
99
|
+
throw new UnauthorizedException(ErrorCode.UNAUTHORIZED);
|
|
100
|
+
}
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
102
|
+
// If no roles required, or S_EVERYONE is set, allow access without authentication
|
|
103
|
+
// This allows public endpoints (without @Roles decorator or with S_EVERYONE) to work
|
|
104
|
+
if (!roles || !roles.some((value) => !!value) || roles.includes(RoleEnum.S_EVERYONE)) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (request) {
|
|
110
|
-
request.user = user;
|
|
111
|
-
}
|
|
108
|
+
// Resolve services lazily (only needed if authentication is required)
|
|
109
|
+
this.resolveServices();
|
|
112
110
|
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
// Get request and check for existing user (from BetterAuth middleware)
|
|
112
|
+
const request = this.getRequest(context);
|
|
113
|
+
const existingUser = request?.user;
|
|
115
114
|
|
|
115
|
+
// If user is already authenticated via BetterAuth middleware, validate roles directly
|
|
116
|
+
if (existingUser && existingUser._authenticatedViaBetterAuth === true) {
|
|
117
|
+
this.handleRequest(null, existingUser, null, context);
|
|
116
118
|
return true;
|
|
117
119
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Verify BetterAuth token (JWT or session) and load the corresponding user
|
|
122
|
-
*
|
|
123
|
-
* This method tries multiple verification strategies:
|
|
124
|
-
* 1. BetterAuth JWT verification (if JWT plugin is enabled)
|
|
125
|
-
* 2. BetterAuth session token lookup (database lookup)
|
|
126
|
-
*
|
|
127
|
-
* @param context - ExecutionContext to extract request from
|
|
128
|
-
* @returns User object if verification succeeds, null otherwise
|
|
129
|
-
*/
|
|
130
|
-
private async verifyBetterAuthTokenFromContext(context: ExecutionContext): Promise<any> {
|
|
131
|
-
if (!this.betterAuthService || !this.mongoConnection) {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
120
|
|
|
135
|
-
try
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (ctx?.req?.headers) {
|
|
144
|
-
authHeader = ctx.req.headers.authorization || ctx.req.headers.Authorization;
|
|
145
|
-
}
|
|
146
|
-
} catch {
|
|
147
|
-
// GraphQL context not available
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Fallback to HTTP context
|
|
151
|
-
if (!authHeader) {
|
|
152
|
-
try {
|
|
153
|
-
const httpRequest = context.switchToHttp().getRequest();
|
|
154
|
-
if (httpRequest?.headers) {
|
|
155
|
-
authHeader = httpRequest.headers.authorization || httpRequest.headers.Authorization;
|
|
156
|
-
}
|
|
157
|
-
} catch {
|
|
158
|
-
// HTTP context not available
|
|
121
|
+
// If BetterAuth is enabled, try BetterAuth verification FIRST
|
|
122
|
+
// This allows IAM-only setups to work without JWT strategy
|
|
123
|
+
if (this.betterAuthService?.isEnabled()) {
|
|
124
|
+
const user = await this.verifyBetterAuthTokenFromContext(context);
|
|
125
|
+
if (user) {
|
|
126
|
+
// BetterAuth token is valid - set the user on the request
|
|
127
|
+
if (request) {
|
|
128
|
+
request.user = user;
|
|
159
129
|
}
|
|
130
|
+
// Validate roles
|
|
131
|
+
this.handleRequest(null, user, null, context);
|
|
132
|
+
return true;
|
|
160
133
|
}
|
|
134
|
+
}
|
|
161
135
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const ctx = gqlContext.getContext();
|
|
179
|
-
if (ctx?.req?.cookies) {
|
|
180
|
-
cookies = ctx.req.cookies;
|
|
181
|
-
}
|
|
182
|
-
} catch {
|
|
183
|
-
// GraphQL context not available
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Fallback to HTTP context
|
|
187
|
-
if (!cookies) {
|
|
188
|
-
try {
|
|
189
|
-
const httpRequest = context.switchToHttp().getRequest();
|
|
190
|
-
if (httpRequest?.cookies) {
|
|
191
|
-
cookies = httpRequest.cookies;
|
|
192
|
-
}
|
|
193
|
-
} catch {
|
|
194
|
-
// HTTP context not available
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Extract session token from cookies (try multiple cookie names)
|
|
199
|
-
if (cookies) {
|
|
200
|
-
// Get the basePath for cookie name (e.g., 'iam' -> 'iam.session_token')
|
|
201
|
-
const basePath = this.betterAuthService.getBasePath?.()?.replace(/^\//, '').replace(/\//g, '.') || 'iam';
|
|
202
|
-
const basePathCookie = `${basePath}.session_token`;
|
|
203
|
-
|
|
204
|
-
token =
|
|
205
|
-
cookies[basePathCookie] ||
|
|
206
|
-
cookies['better-auth.session_token'] ||
|
|
207
|
-
cookies['token'] ||
|
|
208
|
-
undefined;
|
|
136
|
+
// Try Passport JWT authentication (Legacy JWT)
|
|
137
|
+
try {
|
|
138
|
+
const result = super.canActivate(context);
|
|
139
|
+
return isObservable(result) ? await firstValueFrom(result) : await result;
|
|
140
|
+
} catch (passportError) {
|
|
141
|
+
// Check if this is an "Unknown authentication strategy" error
|
|
142
|
+
// This happens in IAM-only setups where JWT strategy is not registered
|
|
143
|
+
const errorMessage = passportError instanceof Error ? passportError.message : String(passportError);
|
|
144
|
+
const isStrategyError = errorMessage.includes('Unknown authentication strategy');
|
|
145
|
+
|
|
146
|
+
// If BetterAuth is enabled but verification failed earlier, or if this is a strategy error
|
|
147
|
+
if (this.betterAuthService?.isEnabled()) {
|
|
148
|
+
// For strategy errors, BetterAuth verification already failed above
|
|
149
|
+
// Rethrow with a more descriptive error
|
|
150
|
+
if (isStrategyError) {
|
|
151
|
+
throw new InvalidTokenException();
|
|
209
152
|
}
|
|
210
|
-
}
|
|
211
153
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (this.betterAuthService.isJwtEnabled()) {
|
|
218
|
-
try {
|
|
219
|
-
const payload = await this.betterAuthService.verifyJwtToken(token);
|
|
220
|
-
if (payload?.sub) {
|
|
221
|
-
const user = await this.loadUserFromPayload(payload);
|
|
222
|
-
if (user) {
|
|
223
|
-
return user;
|
|
224
|
-
}
|
|
154
|
+
// For other errors (e.g., invalid JWT), try BetterAuth as fallback one more time
|
|
155
|
+
const user = await this.verifyBetterAuthTokenFromContext(context);
|
|
156
|
+
if (user) {
|
|
157
|
+
if (request) {
|
|
158
|
+
request.user = user;
|
|
225
159
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Strategy 2: Try session token lookup (database lookup)
|
|
232
|
-
try {
|
|
233
|
-
const sessionResult = await this.betterAuthService.getSessionByToken(token);
|
|
234
|
-
if (sessionResult?.user) {
|
|
235
|
-
return this.loadUserFromSessionResult(sessionResult.user);
|
|
160
|
+
this.handleRequest(null, user, null, context);
|
|
161
|
+
return true;
|
|
236
162
|
}
|
|
237
|
-
} catch {
|
|
238
|
-
// Session lookup failed
|
|
239
163
|
}
|
|
240
164
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
this.logger.debug(
|
|
244
|
-
`BetterAuth token fallback failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
245
|
-
);
|
|
246
|
-
return null;
|
|
165
|
+
// BetterAuth verification also failed - rethrow original error
|
|
166
|
+
throw passportError;
|
|
247
167
|
}
|
|
248
168
|
}
|
|
249
169
|
|
|
250
170
|
/**
|
|
251
|
-
*
|
|
171
|
+
* Verify BetterAuth token (JWT or session) and load the corresponding user.
|
|
172
|
+
*
|
|
173
|
+
* Delegates to BetterAuthTokenService for token extraction and verification.
|
|
174
|
+
* Handles both GraphQL and HTTP contexts.
|
|
252
175
|
*
|
|
253
|
-
* @param
|
|
254
|
-
* @returns User object
|
|
176
|
+
* @param context - ExecutionContext to extract request from
|
|
177
|
+
* @returns User object if verification succeeds, null otherwise
|
|
255
178
|
*/
|
|
256
|
-
private async
|
|
257
|
-
if (!this.
|
|
179
|
+
private async verifyBetterAuthTokenFromContext(context: ExecutionContext): Promise<BetterAuthenticatedUser | null> {
|
|
180
|
+
if (!this.tokenService) {
|
|
258
181
|
return null;
|
|
259
182
|
}
|
|
260
183
|
|
|
261
184
|
try {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (Types.ObjectId.isValid(payload.sub)) {
|
|
267
|
-
user = await usersCollection.findOne({ _id: new Types.ObjectId(payload.sub) });
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// If not found, try by iamId
|
|
271
|
-
if (!user) {
|
|
272
|
-
user = await usersCollection.findOne({ iamId: payload.sub });
|
|
185
|
+
// Extract request from context (supports both GraphQL and HTTP)
|
|
186
|
+
const request = this.extractRequestFromContext(context);
|
|
187
|
+
if (!request) {
|
|
188
|
+
return null;
|
|
273
189
|
}
|
|
274
190
|
|
|
275
|
-
|
|
191
|
+
// Extract token from request
|
|
192
|
+
const { token } = this.tokenService.extractTokenFromRequest(request);
|
|
193
|
+
if (!token) {
|
|
276
194
|
return null;
|
|
277
195
|
}
|
|
278
196
|
|
|
279
|
-
//
|
|
280
|
-
|
|
281
|
-
...user,
|
|
282
|
-
_authenticatedViaBetterAuth: true,
|
|
283
|
-
// Add hasRole method for role checking
|
|
284
|
-
hasRole: (roles: string[]): boolean => {
|
|
285
|
-
if (!user.roles || !Array.isArray(user.roles)) {
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
return roles.some((role) => user.roles.includes(role));
|
|
289
|
-
},
|
|
290
|
-
id: user._id?.toString(),
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
return userObject;
|
|
197
|
+
// Verify token and load user
|
|
198
|
+
return await this.tokenService.verifyAndLoadUser(token);
|
|
294
199
|
} catch (error) {
|
|
295
200
|
this.logger.debug(
|
|
296
|
-
`
|
|
201
|
+
`BetterAuth token verification failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
297
202
|
);
|
|
298
203
|
return null;
|
|
299
204
|
}
|
|
300
205
|
}
|
|
301
206
|
|
|
302
207
|
/**
|
|
303
|
-
*
|
|
208
|
+
* Extracts the request object from ExecutionContext.
|
|
209
|
+
* Handles both GraphQL and HTTP contexts.
|
|
304
210
|
*
|
|
305
|
-
* @param
|
|
306
|
-
* @returns
|
|
211
|
+
* @param context - ExecutionContext
|
|
212
|
+
* @returns Request object with headers and cookies
|
|
307
213
|
*/
|
|
308
|
-
private
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
214
|
+
private extractRequestFromContext(context: ExecutionContext): null | {
|
|
215
|
+
cookies?: Record<string, string>;
|
|
216
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
217
|
+
} {
|
|
218
|
+
// Try GraphQL context first
|
|
313
219
|
try {
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
let user: any = null;
|
|
319
|
-
|
|
320
|
-
// Try to find by email (most reliable)
|
|
321
|
-
if (sessionUser.email) {
|
|
322
|
-
user = await usersCollection.findOne({ email: sessionUser.email });
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// If not found by email, try by iamId
|
|
326
|
-
if (!user && sessionUser.id) {
|
|
327
|
-
user = await usersCollection.findOne({ iamId: sessionUser.id });
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// If still not found, try by _id (if the ID looks like a MongoDB ObjectId)
|
|
331
|
-
if (!user && sessionUser.id && Types.ObjectId.isValid(sessionUser.id)) {
|
|
332
|
-
user = await usersCollection.findOne({ _id: new Types.ObjectId(sessionUser.id) });
|
|
220
|
+
const gqlContext = GqlExecutionContext.create(context);
|
|
221
|
+
const ctx = gqlContext.getContext();
|
|
222
|
+
if (ctx?.req) {
|
|
223
|
+
return ctx.req;
|
|
333
224
|
}
|
|
225
|
+
} catch {
|
|
226
|
+
// GraphQL context not available
|
|
227
|
+
}
|
|
334
228
|
|
|
335
|
-
|
|
336
|
-
|
|
229
|
+
// Fallback to HTTP context
|
|
230
|
+
try {
|
|
231
|
+
const httpRequest = context.switchToHttp().getRequest();
|
|
232
|
+
if (httpRequest) {
|
|
233
|
+
return httpRequest;
|
|
337
234
|
}
|
|
338
|
-
|
|
339
|
-
//
|
|
340
|
-
const userObject = {
|
|
341
|
-
...user,
|
|
342
|
-
_authenticatedViaBetterAuth: true,
|
|
343
|
-
// Add hasRole method for role checking
|
|
344
|
-
hasRole: (roles: string[]): boolean => {
|
|
345
|
-
if (!user.roles || !Array.isArray(user.roles)) {
|
|
346
|
-
return false;
|
|
347
|
-
}
|
|
348
|
-
return roles.some((role) => user.roles.includes(role));
|
|
349
|
-
},
|
|
350
|
-
id: user._id?.toString(),
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
return userObject;
|
|
354
|
-
} catch (error) {
|
|
355
|
-
this.logger.debug(
|
|
356
|
-
`Failed to load user from session: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
357
|
-
);
|
|
358
|
-
return null;
|
|
235
|
+
} catch {
|
|
236
|
+
// HTTP context not available
|
|
359
237
|
}
|
|
238
|
+
|
|
239
|
+
return null;
|
|
360
240
|
}
|
|
361
241
|
|
|
362
242
|
/**
|
|
363
243
|
* Handle request
|
|
364
244
|
*/
|
|
365
|
-
override handleRequest(err, user, info, context) {
|
|
245
|
+
override handleRequest(err: Error | null, user: any, info: any, context: ExecutionContext) {
|
|
366
246
|
// Get roles
|
|
367
247
|
const reflectorRoles = this.reflector.getAll<string[][]>('roles', [context.getHandler(), context.getClass()]);
|
|
368
248
|
const roles: string[] = reflectorRoles[0]
|