@ackplus/nest-auth 1.1.18 → 1.1.20
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/package.json +1 -1
- package/src/lib/admin-console/static/index.html +697 -177
- package/src/lib/audit/services/audit.service.d.ts +15 -0
- package/src/lib/audit/services/audit.service.d.ts.map +1 -0
- package/src/lib/audit/services/audit.service.js +143 -0
- package/src/lib/auth/controllers/auth.controller.d.ts +1 -1
- package/src/lib/auth/controllers/mfa.controller.js +5 -5
- package/src/lib/auth/dto/responses/mfa-status.response.dto.d.ts +2 -2
- package/src/lib/auth/dto/responses/mfa-status.response.dto.d.ts.map +1 -1
- package/src/lib/auth/dto/responses/mfa-status.response.dto.js +5 -5
- package/src/lib/auth/events/index.d.ts +13 -0
- package/src/lib/auth/events/index.d.ts.map +1 -0
- package/src/lib/auth/events/index.js +15 -0
- package/src/lib/auth/events/user-2fa-disabled.event.d.ts +10 -0
- package/src/lib/auth/events/user-2fa-disabled.event.d.ts.map +1 -0
- package/src/lib/auth/events/user-2fa-disabled.event.js +12 -0
- package/src/lib/auth/events/user-2fa-enabled.event.d.ts +13 -0
- package/src/lib/auth/events/user-2fa-enabled.event.d.ts.map +1 -0
- package/src/lib/auth/events/user-2fa-enabled.event.js +15 -0
- package/src/lib/auth/events/user-password-changed.event.d.ts +12 -0
- package/src/lib/auth/events/user-password-changed.event.d.ts.map +1 -0
- package/src/lib/auth/events/user-password-changed.event.js +15 -0
- package/src/lib/auth/guards/auth.guard.d.ts +19 -1
- package/src/lib/auth/guards/auth.guard.d.ts.map +1 -1
- package/src/lib/auth/guards/auth.guard.js +113 -25
- package/src/lib/auth/services/auth.service.d.ts +10 -6
- package/src/lib/auth/services/auth.service.d.ts.map +1 -1
- package/src/lib/auth/services/auth.service.js +313 -133
- package/src/lib/auth/services/mfa.service.d.ts +1 -1
- package/src/lib/auth/services/mfa.service.d.ts.map +1 -1
- package/src/lib/auth/services/mfa.service.js +46 -10
- package/src/lib/auth.constants.d.ts +181 -8
- package/src/lib/auth.constants.d.ts.map +1 -1
- package/src/lib/auth.constants.js +142 -10
- package/src/lib/core/interfaces/auth-module-options.interface.d.ts +170 -0
- package/src/lib/core/interfaces/auth-module-options.interface.d.ts.map +1 -1
- package/src/lib/core/interfaces/session-options.interface.d.ts +52 -0
- package/src/lib/core/interfaces/session-options.interface.d.ts.map +1 -1
- package/src/lib/core/interfaces/token-payload.interface.d.ts +14 -6
- package/src/lib/core/interfaces/token-payload.interface.d.ts.map +1 -1
- package/src/lib/core/services/auth-config.service.js +1 -1
- package/src/lib/nest-auth.module.d.ts.map +1 -1
- package/src/lib/nest-auth.module.js +5 -2
- package/src/lib/session/services/session-manager.service.d.ts +6 -6
- package/src/lib/session/services/session-manager.service.d.ts.map +1 -1
- package/src/lib/session/services/session-manager.service.js +54 -21
- package/src/lib/user/entities/user.entity.d.ts.map +1 -1
- package/src/lib/user/entities/user.entity.js +19 -0
- package/src/lib/user/services/user.service.d.ts +8 -6
- package/src/lib/user/services/user.service.d.ts.map +1 -1
- package/src/lib/user/services/user.service.js +51 -46
|
@@ -30,8 +30,10 @@ const debug_logger_service_1 = require("../../core/services/debug-logger.service
|
|
|
30
30
|
const moment_1 = tslib_1.__importDefault(require("moment"));
|
|
31
31
|
const auth_config_service_1 = require("../../core/services/auth-config.service");
|
|
32
32
|
const cookie_helper_1 = require("../../utils/cookie.helper");
|
|
33
|
+
const user_password_changed_event_1 = require("../events/user-password-changed.event");
|
|
34
|
+
const user_service_1 = require("../../user/services/user.service");
|
|
33
35
|
let AuthService = class AuthService {
|
|
34
|
-
constructor(userRepository, otpRepository, authProviderRegistry, mfaService, sessionManager, jwtService, eventEmitter, tenantService, debugLogger, authConfigService) {
|
|
36
|
+
constructor(userRepository, otpRepository, authProviderRegistry, mfaService, sessionManager, jwtService, eventEmitter, tenantService, debugLogger, authConfigService, userService) {
|
|
35
37
|
this.userRepository = userRepository;
|
|
36
38
|
this.otpRepository = otpRepository;
|
|
37
39
|
this.authProviderRegistry = authProviderRegistry;
|
|
@@ -42,6 +44,7 @@ let AuthService = class AuthService {
|
|
|
42
44
|
this.tenantService = tenantService;
|
|
43
45
|
this.debugLogger = debugLogger;
|
|
44
46
|
this.authConfigService = authConfigService;
|
|
47
|
+
this.userService = userService;
|
|
45
48
|
}
|
|
46
49
|
getUserWithRolesAndPermissions(userId, relations = []) {
|
|
47
50
|
return this.userRepository.findOne({
|
|
@@ -57,14 +60,23 @@ let AuthService = class AuthService {
|
|
|
57
60
|
if (!user) {
|
|
58
61
|
return null;
|
|
59
62
|
}
|
|
60
|
-
|
|
63
|
+
const fullUser = await this.getUserWithRolesAndPermissions(user.id);
|
|
64
|
+
// Apply user.serialize hook if configured
|
|
65
|
+
const config = this.authConfigService.getConfig();
|
|
66
|
+
if (config.user?.serialize) {
|
|
67
|
+
return await config.user.serialize(fullUser);
|
|
68
|
+
}
|
|
69
|
+
return fullUser;
|
|
61
70
|
}
|
|
62
71
|
async signup(input) {
|
|
63
72
|
this.debugLogger.logFunctionEntry('signup', 'AuthService', { email: input.email, phone: input.phone, hasPassword: !!input.password });
|
|
64
73
|
try {
|
|
65
74
|
const config = this.authConfigService.getConfig();
|
|
66
75
|
if (config.registration?.enabled === false) {
|
|
67
|
-
throw new common_1.ForbiddenException(
|
|
76
|
+
throw new common_1.ForbiddenException({
|
|
77
|
+
message: 'Registration is disabled',
|
|
78
|
+
code: auth_constants_1.ERROR_CODES.REGISTRATION_DISABLED,
|
|
79
|
+
});
|
|
68
80
|
}
|
|
69
81
|
const { email, phone, password } = input;
|
|
70
82
|
let { tenantId = null } = input;
|
|
@@ -73,7 +85,10 @@ let AuthService = class AuthService {
|
|
|
73
85
|
this.debugLogger.logAuthOperation('signup', 'email|phone', undefined, { email, phone, resolvedTenantId: tenantId });
|
|
74
86
|
if (!email && !phone) {
|
|
75
87
|
this.debugLogger.error('Signup failed: Neither email nor phone provided', 'AuthService');
|
|
76
|
-
throw new common_1.BadRequestException(
|
|
88
|
+
throw new common_1.BadRequestException({
|
|
89
|
+
message: 'Either email or phone must be provided',
|
|
90
|
+
code: auth_constants_1.ERROR_CODES.EMAIL_OR_PHONE_REQUIRED,
|
|
91
|
+
});
|
|
77
92
|
}
|
|
78
93
|
let provider = null;
|
|
79
94
|
let providerUserId = null;
|
|
@@ -87,31 +102,42 @@ let AuthService = class AuthService {
|
|
|
87
102
|
}
|
|
88
103
|
if (!provider) {
|
|
89
104
|
this.debugLogger.error('Provider not found for signup', 'AuthService', { email: !!email, phone: !!phone });
|
|
90
|
-
throw new common_1.InternalServerErrorException(
|
|
105
|
+
throw new common_1.InternalServerErrorException({
|
|
106
|
+
message: 'Phone or email authentication is not enabled',
|
|
107
|
+
code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
|
|
108
|
+
});
|
|
91
109
|
}
|
|
92
110
|
this.debugLogger.debug('Checking for existing identity', 'AuthService', { providerUserId });
|
|
93
111
|
const identity = await provider.findIdentity(providerUserId);
|
|
94
112
|
if (identity) {
|
|
95
113
|
this.debugLogger.warn('Identity already exists', 'AuthService', { email: !!email, phone: !!phone, tenantId });
|
|
96
114
|
if (email) {
|
|
97
|
-
throw new common_1.BadRequestException(
|
|
115
|
+
throw new common_1.BadRequestException({
|
|
116
|
+
message: 'Email already exists in this tenant',
|
|
117
|
+
code: auth_constants_1.ERROR_CODES.EMAIL_ALREADY_EXISTS,
|
|
118
|
+
});
|
|
98
119
|
}
|
|
99
120
|
if (phone) {
|
|
100
|
-
throw new common_1.BadRequestException(
|
|
121
|
+
throw new common_1.BadRequestException({
|
|
122
|
+
message: 'Phone number already exists in this tenant',
|
|
123
|
+
code: auth_constants_1.ERROR_CODES.PHONE_ALREADY_EXISTS,
|
|
124
|
+
});
|
|
101
125
|
}
|
|
102
126
|
}
|
|
103
|
-
this.debugLogger.debug('Creating new user', 'AuthService', { email: !!email, phone: !!phone, tenantId });
|
|
104
|
-
|
|
127
|
+
this.debugLogger.debug('Creating new user via UserService', 'AuthService', { email: !!email, phone: !!phone, tenantId });
|
|
128
|
+
// Use UserService to create user, which handles hooks and password hashing
|
|
129
|
+
// We pass the plain password, UserService will hash it if provided
|
|
130
|
+
let user = await this.userService.createUser({
|
|
105
131
|
email,
|
|
106
132
|
phone,
|
|
107
133
|
tenantId,
|
|
108
134
|
isVerified: false,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
await this.userRepository.save(user);
|
|
135
|
+
password
|
|
136
|
+
}, input);
|
|
112
137
|
this.debugLogger.info('User created successfully', 'AuthService', { userId: user.id, tenantId });
|
|
113
138
|
user = await this.getUserWithRolesAndPermissions(user.id);
|
|
114
139
|
this.debugLogger.debug('Linking user to provider', 'AuthService', { userId: user.id, providerName: provider.providerName });
|
|
140
|
+
// Note: UserService might have already created the identity, but we ensure it's linked here
|
|
115
141
|
await provider.linkToUser(user.id, providerUserId);
|
|
116
142
|
this.debugLogger.debug('Creating session for new user', 'AuthService', { userId: user.id });
|
|
117
143
|
const session = await this.sessionManager.createSessionFromUser(user);
|
|
@@ -130,14 +156,21 @@ let AuthService = class AuthService {
|
|
|
130
156
|
isRequiresMfa
|
|
131
157
|
}));
|
|
132
158
|
this.debugLogger.logFunctionExit('signup', 'AuthService', { userId: user.id, isRequiresMfa });
|
|
133
|
-
|
|
159
|
+
// Build default response
|
|
160
|
+
let response = {
|
|
134
161
|
accessToken: tokens.accessToken,
|
|
135
162
|
refreshToken: tokens.refreshToken,
|
|
136
163
|
isRequiresMfa: isRequiresMfa,
|
|
137
164
|
};
|
|
165
|
+
// Apply auth.transformResponse hook if configured
|
|
166
|
+
if (config.auth?.transformResponse) {
|
|
167
|
+
response = await config.auth.transformResponse(response, user, session);
|
|
168
|
+
}
|
|
169
|
+
return response;
|
|
138
170
|
}
|
|
139
171
|
catch (error) {
|
|
140
172
|
this.debugLogger.logError(error, 'signup', { email: input.email, phone: input.phone });
|
|
173
|
+
this.handleError(error, 'signup');
|
|
141
174
|
throw error;
|
|
142
175
|
}
|
|
143
176
|
}
|
|
@@ -145,76 +178,100 @@ let AuthService = class AuthService {
|
|
|
145
178
|
const { credentials, providerName, createUserIfNotExists = false } = input;
|
|
146
179
|
this.debugLogger.logFunctionEntry('login', 'AuthService', { providerName, createUserIfNotExists });
|
|
147
180
|
let { tenantId = null } = input;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
const authProviderUser = await provider.validate(credentials);
|
|
160
|
-
const identity = await provider.findIdentity(authProviderUser.userId);
|
|
161
|
-
let user = identity?.user || null;
|
|
162
|
-
if (!user) {
|
|
163
|
-
if (!createUserIfNotExists) {
|
|
164
|
-
throw new common_1.UnauthorizedException('Invalid credentials');
|
|
181
|
+
try {
|
|
182
|
+
// Resolve tenant ID - use provided or default
|
|
183
|
+
tenantId = await this.tenantService.resolveTenantId(tenantId);
|
|
184
|
+
this.debugLogger.logAuthOperation('login', providerName, undefined, { resolvedTenantId: tenantId, createUserIfNotExists });
|
|
185
|
+
const provider = this.authProviderRegistry.getProvider(providerName);
|
|
186
|
+
if (!provider) {
|
|
187
|
+
throw new common_1.UnauthorizedException({
|
|
188
|
+
message: 'Invalid authentication providerName or provider is not enabled',
|
|
189
|
+
code: auth_constants_1.ERROR_CODES.INVALID_PROVIDER,
|
|
190
|
+
});
|
|
165
191
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
// Set Mfa enbale if requred for all user, set in properly in session
|
|
182
|
-
await this.sessionManager.updateSession(session.id, {
|
|
183
|
-
data: { ...session.data, isMfaEnabled: true }
|
|
184
|
-
});
|
|
185
|
-
const trustCookieName = auth_config_service_1.AuthConfigService.getOptions().mfa?.trustDeviceStorageName || auth_constants_1.NEST_AUTH_TRUST_DEVICE_KEY;
|
|
186
|
-
const req = request_context_1.RequestContext.currentRequest();
|
|
187
|
-
let trustToken = cookie_helper_1.CookieHelper.get(req, trustCookieName);
|
|
188
|
-
// If not in cookie, check header
|
|
189
|
-
if (!trustToken) {
|
|
190
|
-
trustToken = req.headers[trustCookieName];
|
|
191
|
-
}
|
|
192
|
-
if (trustToken) {
|
|
193
|
-
const isTrusted = await this.mfaService.validateTrustedDevice(user.id, trustToken);
|
|
194
|
-
if (isTrusted) {
|
|
195
|
-
isRequiresMfa = false;
|
|
196
|
-
// Update session to indicate MFA is verified by trust
|
|
197
|
-
await this.sessionManager.updateSession(session.id, {
|
|
198
|
-
data: { ...session.data, isMfaVerified: true }
|
|
192
|
+
const requiredFields = provider.getRequiredFields();
|
|
193
|
+
if (!requiredFields.every(field => credentials[field])) {
|
|
194
|
+
throw new common_1.BadRequestException({
|
|
195
|
+
message: `Missing ${requiredFields.join(', ')} required fields`,
|
|
196
|
+
code: auth_constants_1.ERROR_CODES.MISSING_REQUIRED_FIELDS,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
const authProviderUser = await provider.validate(credentials);
|
|
200
|
+
const identity = await provider.findIdentity(authProviderUser.userId);
|
|
201
|
+
let user = identity?.user || null;
|
|
202
|
+
if (!user) {
|
|
203
|
+
if (!createUserIfNotExists) {
|
|
204
|
+
throw new common_1.UnauthorizedException({
|
|
205
|
+
message: 'Invalid credentials',
|
|
206
|
+
code: auth_constants_1.ERROR_CODES.INVALID_CREDENTIALS,
|
|
199
207
|
});
|
|
200
208
|
}
|
|
209
|
+
// Create new user if not exists and link to provider
|
|
210
|
+
user = await this.handleSocialLogin(provider, authProviderUser, tenantId);
|
|
211
|
+
}
|
|
212
|
+
if (user.isActive === false) {
|
|
213
|
+
throw new common_1.UnauthorizedException({
|
|
214
|
+
message: 'Your account is suspended, please contact support',
|
|
215
|
+
code: auth_constants_1.ERROR_CODES.ACCOUNT_INACTIVE,
|
|
216
|
+
});
|
|
201
217
|
}
|
|
218
|
+
user = await this.getUserWithRolesAndPermissions(user.id);
|
|
219
|
+
let isRequiresMfa = await this.mfaService.isRequiresMfa(user.id);
|
|
220
|
+
user.isMfaEnabled = isRequiresMfa;
|
|
221
|
+
let session = await this.sessionManager.createSessionFromUser(user);
|
|
222
|
+
// Check for trusted device cookie or header if MFA is required
|
|
223
|
+
if (isRequiresMfa) {
|
|
224
|
+
// Set Mfa enbale if requred for all user, set in properly in session
|
|
225
|
+
await this.sessionManager.updateSession(session.id, {
|
|
226
|
+
data: { ...session.data, isMfaEnabled: true }
|
|
227
|
+
});
|
|
228
|
+
const trustCookieName = auth_config_service_1.AuthConfigService.getOptions().mfa?.trustDeviceStorageName || auth_constants_1.NEST_AUTH_TRUST_DEVICE_KEY;
|
|
229
|
+
const req = request_context_1.RequestContext.currentRequest();
|
|
230
|
+
let trustToken = cookie_helper_1.CookieHelper.get(req, trustCookieName);
|
|
231
|
+
// If not in cookie, check header
|
|
232
|
+
if (!trustToken) {
|
|
233
|
+
trustToken = req.headers[trustCookieName];
|
|
234
|
+
}
|
|
235
|
+
if (trustToken) {
|
|
236
|
+
const isTrusted = await this.mfaService.validateTrustedDevice(user.id, trustToken);
|
|
237
|
+
if (isTrusted) {
|
|
238
|
+
isRequiresMfa = false;
|
|
239
|
+
// Update session to indicate MFA is verified by trust
|
|
240
|
+
session = await this.sessionManager.updateSession(session.id, {
|
|
241
|
+
data: { ...session.data, isMfaVerified: true }
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const tokens = await this.generateTokensFromSession(session);
|
|
247
|
+
// Emit login event
|
|
248
|
+
await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.LOGGED_IN, new user_logged_in_event_1.UserLoggedInEvent({
|
|
249
|
+
user,
|
|
250
|
+
tenantId: user.tenantId,
|
|
251
|
+
input,
|
|
252
|
+
provider,
|
|
253
|
+
session,
|
|
254
|
+
tokens,
|
|
255
|
+
isRequiresMfa
|
|
256
|
+
}));
|
|
257
|
+
// Build default response
|
|
258
|
+
let response = {
|
|
259
|
+
accessToken: tokens.accessToken,
|
|
260
|
+
refreshToken: tokens.refreshToken,
|
|
261
|
+
isRequiresMfa: isRequiresMfa,
|
|
262
|
+
};
|
|
263
|
+
// Apply auth.transformResponse hook if configured
|
|
264
|
+
const config = this.authConfigService.getConfig();
|
|
265
|
+
if (config.auth?.transformResponse) {
|
|
266
|
+
response = await config.auth.transformResponse(response, user, session);
|
|
267
|
+
}
|
|
268
|
+
return response;
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
this.debugLogger.logError(error, 'login', { providerName, createUserIfNotExists });
|
|
272
|
+
this.handleError(error, 'login');
|
|
273
|
+
throw error;
|
|
202
274
|
}
|
|
203
|
-
// Emit login event
|
|
204
|
-
await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.LOGGED_IN, new user_logged_in_event_1.UserLoggedInEvent({
|
|
205
|
-
user,
|
|
206
|
-
tenantId: user.tenantId,
|
|
207
|
-
input,
|
|
208
|
-
provider,
|
|
209
|
-
session,
|
|
210
|
-
tokens,
|
|
211
|
-
isRequiresMfa
|
|
212
|
-
}));
|
|
213
|
-
return {
|
|
214
|
-
accessToken: tokens.accessToken,
|
|
215
|
-
refreshToken: tokens.refreshToken,
|
|
216
|
-
isRequiresMfa: isRequiresMfa,
|
|
217
|
-
};
|
|
218
275
|
}
|
|
219
276
|
async verify2fa(input) {
|
|
220
277
|
this.debugLogger.logFunctionEntry('verify2fa', 'AuthService', { method: input.method });
|
|
@@ -224,7 +281,7 @@ let AuthService = class AuthService {
|
|
|
224
281
|
this.debugLogger.error('Session not found for 2FA verification', 'AuthService');
|
|
225
282
|
throw new common_1.UnauthorizedException({
|
|
226
283
|
message: 'Session not found',
|
|
227
|
-
code: auth_constants_1.
|
|
284
|
+
code: auth_constants_1.ERROR_CODES.SESSION_NOT_FOUND,
|
|
228
285
|
});
|
|
229
286
|
}
|
|
230
287
|
this.debugLogger.debug('Verifying MFA code', 'AuthService', { userId: session.userId, method: input.method });
|
|
@@ -233,7 +290,7 @@ let AuthService = class AuthService {
|
|
|
233
290
|
this.debugLogger.warn('Invalid MFA code provided', 'AuthService', { userId: session.userId, method: input.method });
|
|
234
291
|
throw new common_1.UnauthorizedException({
|
|
235
292
|
message: 'Invalid MFA code',
|
|
236
|
-
code: auth_constants_1.
|
|
293
|
+
code: auth_constants_1.ERROR_CODES.MFA_CODE_INVALID,
|
|
237
294
|
});
|
|
238
295
|
}
|
|
239
296
|
this.debugLogger.debug('Updating session with MFA verification', 'AuthService', { sessionId: session.id });
|
|
@@ -255,7 +312,7 @@ let AuthService = class AuthService {
|
|
|
255
312
|
// Emit 2FA verified event
|
|
256
313
|
this.debugLogger.debug('Emitting 2FA verified event', 'AuthService', { userId: user.id });
|
|
257
314
|
await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.TWO_FACTOR_VERIFIED, new user_2fa_verified_event_1.User2faVerifiedEvent({
|
|
258
|
-
user,
|
|
315
|
+
user: user,
|
|
259
316
|
tenantId: user.tenantId,
|
|
260
317
|
input,
|
|
261
318
|
session,
|
|
@@ -270,13 +327,17 @@ let AuthService = class AuthService {
|
|
|
270
327
|
}
|
|
271
328
|
catch (error) {
|
|
272
329
|
this.debugLogger.logError(error, 'verify2fa', { method: input.method });
|
|
330
|
+
this.handleError(error, 'mfa');
|
|
273
331
|
throw error;
|
|
274
332
|
}
|
|
275
333
|
}
|
|
276
334
|
async send2faCode(userId, method) {
|
|
277
335
|
const user = await this.userRepository.findOne({ where: { id: userId } });
|
|
278
336
|
if (!user) {
|
|
279
|
-
throw new common_1.UnauthorizedException(
|
|
337
|
+
throw new common_1.UnauthorizedException({
|
|
338
|
+
message: 'User not found',
|
|
339
|
+
code: auth_constants_1.ERROR_CODES.USER_NOT_FOUND,
|
|
340
|
+
});
|
|
280
341
|
}
|
|
281
342
|
await this.mfaService.sendMfaCode(user.id, method);
|
|
282
343
|
return true;
|
|
@@ -309,7 +370,7 @@ let AuthService = class AuthService {
|
|
|
309
370
|
this.debugLogger.error('No refresh token provided', 'AuthService');
|
|
310
371
|
throw new common_1.UnauthorizedException({
|
|
311
372
|
message: 'No refresh token provided',
|
|
312
|
-
code: auth_constants_1.REFRESH_TOKEN_INVALID,
|
|
373
|
+
code: auth_constants_1.ERROR_CODES.REFRESH_TOKEN_INVALID,
|
|
313
374
|
});
|
|
314
375
|
}
|
|
315
376
|
this.debugLogger.debug('Verifying refresh token', 'AuthService');
|
|
@@ -321,20 +382,18 @@ let AuthService = class AuthService {
|
|
|
321
382
|
this.debugLogger.warn('Invalid or expired refresh token', 'AuthService');
|
|
322
383
|
throw new common_1.UnauthorizedException({
|
|
323
384
|
message: 'Invalid or expired refresh token',
|
|
324
|
-
code: auth_constants_1.REFRESH_TOKEN_EXPIRED,
|
|
385
|
+
code: auth_constants_1.ERROR_CODES.REFRESH_TOKEN_EXPIRED,
|
|
325
386
|
});
|
|
326
387
|
}
|
|
327
388
|
const session = await this.sessionManager.getSession(payload.sessionId);
|
|
328
389
|
if (!session) {
|
|
329
390
|
throw new common_1.UnauthorizedException({
|
|
330
391
|
message: 'Invalid refresh token',
|
|
331
|
-
code: auth_constants_1.REFRESH_TOKEN_INVALID,
|
|
392
|
+
code: auth_constants_1.ERROR_CODES.REFRESH_TOKEN_INVALID,
|
|
332
393
|
});
|
|
333
394
|
}
|
|
334
|
-
//
|
|
335
|
-
const newSession = await this.sessionManager.
|
|
336
|
-
// Revoke old session
|
|
337
|
-
await this.sessionManager.revokeSession(session.id);
|
|
395
|
+
// Refresh existing session
|
|
396
|
+
const newSession = await this.sessionManager.refreshSession(session);
|
|
338
397
|
// Generate new tokens
|
|
339
398
|
this.debugLogger.debug('Generating new tokens from refreshed session', 'AuthService', { sessionId: newSession.id });
|
|
340
399
|
const tokens = await this.generateTokensFromSession(newSession);
|
|
@@ -350,6 +409,7 @@ let AuthService = class AuthService {
|
|
|
350
409
|
}
|
|
351
410
|
catch (error) {
|
|
352
411
|
this.debugLogger.logError(error, 'refreshToken', { hasRefreshToken: !!refreshToken });
|
|
412
|
+
this.handleError(error, 'refresh');
|
|
353
413
|
throw error;
|
|
354
414
|
}
|
|
355
415
|
}
|
|
@@ -358,20 +418,32 @@ let AuthService = class AuthService {
|
|
|
358
418
|
try {
|
|
359
419
|
const currentUser = request_context_1.RequestContext.currentUser();
|
|
360
420
|
if (!currentUser?.id) {
|
|
361
|
-
throw new common_1.UnauthorizedException(
|
|
421
|
+
throw new common_1.UnauthorizedException({
|
|
422
|
+
message: 'User not found',
|
|
423
|
+
code: auth_constants_1.ERROR_CODES.USER_NOT_FOUND,
|
|
424
|
+
});
|
|
362
425
|
}
|
|
363
426
|
const user = await this.userRepository.findOne({
|
|
364
427
|
where: { id: currentUser.id },
|
|
365
428
|
});
|
|
366
429
|
if (!user) {
|
|
367
|
-
throw new common_1.UnauthorizedException(
|
|
430
|
+
throw new common_1.UnauthorizedException({
|
|
431
|
+
message: 'User not found',
|
|
432
|
+
code: auth_constants_1.ERROR_CODES.USER_NOT_FOUND,
|
|
433
|
+
});
|
|
368
434
|
}
|
|
369
435
|
const isValid = await user.validatePassword(input.currentPassword);
|
|
370
436
|
if (!isValid) {
|
|
371
|
-
throw new common_1.BadRequestException(
|
|
437
|
+
throw new common_1.BadRequestException({
|
|
438
|
+
message: 'Current password is incorrect',
|
|
439
|
+
code: auth_constants_1.ERROR_CODES.CURRENT_PASSWORD_INCORRECT,
|
|
440
|
+
});
|
|
372
441
|
}
|
|
373
442
|
if (input.currentPassword === input.newPassword) {
|
|
374
|
-
throw new common_1.BadRequestException(
|
|
443
|
+
throw new common_1.BadRequestException({
|
|
444
|
+
message: 'New password must be different from the current password',
|
|
445
|
+
code: auth_constants_1.ERROR_CODES.NEW_PASSWORD_SAME_AS_CURRENT,
|
|
446
|
+
});
|
|
375
447
|
}
|
|
376
448
|
await user.setPassword(input.newPassword);
|
|
377
449
|
await this.userRepository.save(user);
|
|
@@ -380,6 +452,10 @@ let AuthService = class AuthService {
|
|
|
380
452
|
const session = await this.sessionManager.createSessionFromUser(hydratedUser);
|
|
381
453
|
const tokens = await this.generateTokensFromSession(session);
|
|
382
454
|
const isRequiresMfa = await this.mfaService.isRequiresMfa(user.id);
|
|
455
|
+
await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.PASSWORD_CHANGED, new user_password_changed_event_1.UserPasswordChangedEvent({
|
|
456
|
+
user,
|
|
457
|
+
initiatedBy: 'user'
|
|
458
|
+
}));
|
|
383
459
|
this.debugLogger.logFunctionExit('changePassword', 'AuthService', { userId: user.id });
|
|
384
460
|
return {
|
|
385
461
|
accessToken: tokens.accessToken,
|
|
@@ -389,6 +465,7 @@ let AuthService = class AuthService {
|
|
|
389
465
|
}
|
|
390
466
|
catch (error) {
|
|
391
467
|
this.debugLogger.logError(error, 'changePassword');
|
|
468
|
+
this.handleError(error, 'password_change');
|
|
392
469
|
throw error;
|
|
393
470
|
}
|
|
394
471
|
}
|
|
@@ -407,17 +484,29 @@ let AuthService = class AuthService {
|
|
|
407
484
|
provider = this.authProviderRegistry.getProvider(auth_constants_1.EMAIL_AUTH_PROVIDER);
|
|
408
485
|
}
|
|
409
486
|
else {
|
|
410
|
-
throw new common_1.BadRequestException(
|
|
487
|
+
throw new common_1.BadRequestException({
|
|
488
|
+
message: 'Either email or phone must be provided',
|
|
489
|
+
code: auth_constants_1.ERROR_CODES.EMAIL_OR_PHONE_REQUIRED,
|
|
490
|
+
});
|
|
411
491
|
}
|
|
412
492
|
if (!provider) {
|
|
413
|
-
throw new common_1.BadRequestException(
|
|
493
|
+
throw new common_1.BadRequestException({
|
|
494
|
+
message: 'Phone or email authentication is not enabled',
|
|
495
|
+
code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
|
|
496
|
+
});
|
|
414
497
|
}
|
|
415
498
|
if (!provider.enabled) {
|
|
416
499
|
if (email) {
|
|
417
|
-
throw new common_1.BadRequestException(
|
|
500
|
+
throw new common_1.BadRequestException({
|
|
501
|
+
message: 'Email authentication is not enabled',
|
|
502
|
+
code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
|
|
503
|
+
});
|
|
418
504
|
}
|
|
419
505
|
else if (phone) {
|
|
420
|
-
throw new common_1.BadRequestException(
|
|
506
|
+
throw new common_1.BadRequestException({
|
|
507
|
+
message: 'Phone authentication is not enabled',
|
|
508
|
+
code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
|
|
509
|
+
});
|
|
421
510
|
}
|
|
422
511
|
}
|
|
423
512
|
const identity = await provider.findIdentity(email || phone);
|
|
@@ -449,6 +538,7 @@ let AuthService = class AuthService {
|
|
|
449
538
|
}
|
|
450
539
|
catch (error) {
|
|
451
540
|
this.debugLogger.logError(error, 'forgotPassword', { email: input.email, phone: input.phone });
|
|
541
|
+
this.handleError(error, 'password_reset');
|
|
452
542
|
throw error;
|
|
453
543
|
}
|
|
454
544
|
}
|
|
@@ -460,7 +550,10 @@ let AuthService = class AuthService {
|
|
|
460
550
|
// Resolve tenant ID - use provided or default
|
|
461
551
|
tenantId = await this.tenantService.resolveTenantId(tenantId);
|
|
462
552
|
if (!email && !phone) {
|
|
463
|
-
throw new common_1.BadRequestException(
|
|
553
|
+
throw new common_1.BadRequestException({
|
|
554
|
+
message: 'Either email or phone must be provided',
|
|
555
|
+
code: auth_constants_1.ERROR_CODES.EMAIL_OR_PHONE_REQUIRED,
|
|
556
|
+
});
|
|
464
557
|
}
|
|
465
558
|
let provider = null;
|
|
466
559
|
if (phone) {
|
|
@@ -470,11 +563,17 @@ let AuthService = class AuthService {
|
|
|
470
563
|
provider = this.authProviderRegistry.getProvider(auth_constants_1.EMAIL_AUTH_PROVIDER);
|
|
471
564
|
}
|
|
472
565
|
if (!provider) {
|
|
473
|
-
throw new common_1.BadRequestException(
|
|
566
|
+
throw new common_1.BadRequestException({
|
|
567
|
+
message: 'Phone or email authentication is not enabled',
|
|
568
|
+
code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
|
|
569
|
+
});
|
|
474
570
|
}
|
|
475
571
|
const identity = await provider.findIdentity(email || phone);
|
|
476
572
|
if (!identity) {
|
|
477
|
-
throw new common_1.BadRequestException(
|
|
573
|
+
throw new common_1.BadRequestException({
|
|
574
|
+
message: 'Invalid reset request',
|
|
575
|
+
code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_INVALID_REQUEST,
|
|
576
|
+
});
|
|
478
577
|
}
|
|
479
578
|
const validOtp = await this.otpRepository.findOne({
|
|
480
579
|
where: {
|
|
@@ -486,10 +585,16 @@ let AuthService = class AuthService {
|
|
|
486
585
|
relations: ['user']
|
|
487
586
|
});
|
|
488
587
|
if (!validOtp) {
|
|
489
|
-
throw new common_1.BadRequestException(
|
|
588
|
+
throw new common_1.BadRequestException({
|
|
589
|
+
message: 'Invalid OTP code',
|
|
590
|
+
code: auth_constants_1.ERROR_CODES.OTP_INVALID,
|
|
591
|
+
});
|
|
490
592
|
}
|
|
491
593
|
if ((0, moment_1.default)(validOtp.expiresAt).isBefore(new Date())) {
|
|
492
|
-
throw new common_1.BadRequestException(
|
|
594
|
+
throw new common_1.BadRequestException({
|
|
595
|
+
message: 'OTP code expired',
|
|
596
|
+
code: auth_constants_1.ERROR_CODES.OTP_EXPIRED,
|
|
597
|
+
});
|
|
493
598
|
}
|
|
494
599
|
const user = validOtp.user;
|
|
495
600
|
// Generate JWT-based password reset token
|
|
@@ -510,6 +615,7 @@ let AuthService = class AuthService {
|
|
|
510
615
|
}
|
|
511
616
|
catch (error) {
|
|
512
617
|
this.debugLogger.logError(error, 'verifyForgotPasswordOtp', { email: input.email, phone: input.phone });
|
|
618
|
+
this.handleError(error, 'password_reset');
|
|
513
619
|
throw error;
|
|
514
620
|
}
|
|
515
621
|
}
|
|
@@ -521,7 +627,10 @@ let AuthService = class AuthService {
|
|
|
521
627
|
// Resolve tenant ID - use provided or default
|
|
522
628
|
tenantId = await this.tenantService.resolveTenantId(tenantId);
|
|
523
629
|
if (!email && !phone) {
|
|
524
|
-
throw new common_1.BadRequestException(
|
|
630
|
+
throw new common_1.BadRequestException({
|
|
631
|
+
message: 'Either email or phone must be provided',
|
|
632
|
+
code: auth_constants_1.ERROR_CODES.EMAIL_OR_PHONE_REQUIRED,
|
|
633
|
+
});
|
|
525
634
|
}
|
|
526
635
|
// Find user by email or phone
|
|
527
636
|
const user = await this.userRepository.findOne({
|
|
@@ -531,7 +640,10 @@ let AuthService = class AuthService {
|
|
|
531
640
|
]
|
|
532
641
|
});
|
|
533
642
|
if (!user) {
|
|
534
|
-
throw new common_1.BadRequestException(
|
|
643
|
+
throw new common_1.BadRequestException({
|
|
644
|
+
message: 'Invalid reset request',
|
|
645
|
+
code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_INVALID_REQUEST,
|
|
646
|
+
});
|
|
535
647
|
}
|
|
536
648
|
// Find valid OTP
|
|
537
649
|
const validOtp = await this.otpRepository.findOne({
|
|
@@ -544,7 +656,10 @@ let AuthService = class AuthService {
|
|
|
544
656
|
}
|
|
545
657
|
});
|
|
546
658
|
if (!validOtp) {
|
|
547
|
-
throw new common_1.BadRequestException(
|
|
659
|
+
throw new common_1.BadRequestException({
|
|
660
|
+
message: 'Invalid or expired OTP',
|
|
661
|
+
code: auth_constants_1.ERROR_CODES.OTP_INVALID,
|
|
662
|
+
});
|
|
548
663
|
}
|
|
549
664
|
// Update password
|
|
550
665
|
await user.setPassword(newPassword);
|
|
@@ -563,6 +678,7 @@ let AuthService = class AuthService {
|
|
|
563
678
|
}
|
|
564
679
|
catch (error) {
|
|
565
680
|
this.debugLogger.logError(error, 'resetPassword', { email: input.email, phone: input.phone });
|
|
681
|
+
this.handleError(error, 'password_reset');
|
|
566
682
|
throw error;
|
|
567
683
|
}
|
|
568
684
|
}
|
|
@@ -576,23 +692,35 @@ let AuthService = class AuthService {
|
|
|
576
692
|
decoded = await this.jwtService.verifyPasswordResetToken(token);
|
|
577
693
|
}
|
|
578
694
|
catch (error) {
|
|
579
|
-
throw new common_1.BadRequestException(
|
|
695
|
+
throw new common_1.BadRequestException({
|
|
696
|
+
message: 'Invalid or expired reset token',
|
|
697
|
+
code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_TOKEN_INVALID,
|
|
698
|
+
});
|
|
580
699
|
}
|
|
581
700
|
if (decoded.type !== 'password-reset') {
|
|
582
|
-
throw new common_1.BadRequestException(
|
|
701
|
+
throw new common_1.BadRequestException({
|
|
702
|
+
message: 'Invalid token type',
|
|
703
|
+
code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_TOKEN_INVALID,
|
|
704
|
+
});
|
|
583
705
|
}
|
|
584
706
|
// Get user
|
|
585
707
|
const user = await this.userRepository.findOne({
|
|
586
708
|
where: { id: decoded.userId }
|
|
587
709
|
});
|
|
588
710
|
if (!user) {
|
|
589
|
-
throw new common_1.BadRequestException(
|
|
711
|
+
throw new common_1.BadRequestException({
|
|
712
|
+
message: 'User not found',
|
|
713
|
+
code: auth_constants_1.ERROR_CODES.USER_NOT_FOUND,
|
|
714
|
+
});
|
|
590
715
|
}
|
|
591
716
|
// Verify password hasn't changed since token was issued
|
|
592
717
|
// This makes the token single-use in practice
|
|
593
718
|
const currentPasswordHashPrefix = user.passwordHash ? user.passwordHash.substring(0, 10) : '';
|
|
594
719
|
if (decoded.passwordHashPrefix !== currentPasswordHashPrefix) {
|
|
595
|
-
throw new common_1.BadRequestException(
|
|
720
|
+
throw new common_1.BadRequestException({
|
|
721
|
+
message: 'Reset token is no longer valid',
|
|
722
|
+
code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_TOKEN_INVALID,
|
|
723
|
+
});
|
|
596
724
|
}
|
|
597
725
|
// Update password
|
|
598
726
|
await user.setPassword(newPassword);
|
|
@@ -608,6 +736,7 @@ let AuthService = class AuthService {
|
|
|
608
736
|
}
|
|
609
737
|
catch (error) {
|
|
610
738
|
this.debugLogger.logError(error, 'resetPasswordWithToken');
|
|
739
|
+
this.handleError(error, 'password_reset');
|
|
611
740
|
throw error;
|
|
612
741
|
}
|
|
613
742
|
}
|
|
@@ -616,7 +745,7 @@ let AuthService = class AuthService {
|
|
|
616
745
|
const user = await this.getUser();
|
|
617
746
|
// Emit logout event
|
|
618
747
|
await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.LOGGED_OUT, new logged_out_event_1.LoggedOutEvent({
|
|
619
|
-
user,
|
|
748
|
+
user: user,
|
|
620
749
|
tenantId: user?.tenantId,
|
|
621
750
|
session,
|
|
622
751
|
logoutType,
|
|
@@ -630,20 +759,25 @@ let AuthService = class AuthService {
|
|
|
630
759
|
async logoutAll(userId, logoutType = 'user', reason) {
|
|
631
760
|
const session = request_context_1.RequestContext.currentSession();
|
|
632
761
|
if (!session) {
|
|
633
|
-
throw new common_1.UnauthorizedException(
|
|
762
|
+
throw new common_1.UnauthorizedException({
|
|
763
|
+
message: 'Session not found',
|
|
764
|
+
code: auth_constants_1.ERROR_CODES.SESSION_NOT_FOUND,
|
|
765
|
+
});
|
|
634
766
|
}
|
|
635
767
|
const sessions = await this.sessionManager.getUserSessions(userId);
|
|
636
768
|
await this.sessionManager.revokeAllUserSessions(userId);
|
|
637
|
-
const user = await this.
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
769
|
+
const user = await this.userRepository.findOne({ where: { id: userId } });
|
|
770
|
+
if (user) {
|
|
771
|
+
// Emit logout event
|
|
772
|
+
await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.LOGGED_OUT_ALL, new logged_out_all_event_1.LoggedOutAllEvent({
|
|
773
|
+
user,
|
|
774
|
+
tenantId: user.tenantId,
|
|
775
|
+
logoutType,
|
|
776
|
+
reason,
|
|
777
|
+
currentSessionId: session.id,
|
|
778
|
+
sessions,
|
|
779
|
+
}));
|
|
780
|
+
}
|
|
647
781
|
return true;
|
|
648
782
|
}
|
|
649
783
|
async sendEmailVerification(input) {
|
|
@@ -651,14 +785,23 @@ let AuthService = class AuthService {
|
|
|
651
785
|
try {
|
|
652
786
|
const user = request_context_1.RequestContext.currentUser();
|
|
653
787
|
if (!user) {
|
|
654
|
-
throw new common_1.UnauthorizedException(
|
|
788
|
+
throw new common_1.UnauthorizedException({
|
|
789
|
+
message: 'User not authenticated',
|
|
790
|
+
code: auth_constants_1.ERROR_CODES.UNAUTHORIZED,
|
|
791
|
+
});
|
|
655
792
|
}
|
|
656
793
|
const fullUser = await this.getUserWithRolesAndPermissions(user.id);
|
|
657
794
|
if (!fullUser.email) {
|
|
658
|
-
throw new common_1.BadRequestException(
|
|
795
|
+
throw new common_1.BadRequestException({
|
|
796
|
+
message: 'User does not have an email address',
|
|
797
|
+
code: auth_constants_1.ERROR_CODES.NO_EMAIL_ADDRESS,
|
|
798
|
+
});
|
|
659
799
|
}
|
|
660
800
|
if (fullUser.emailVerifiedAt) {
|
|
661
|
-
throw new common_1.BadRequestException(
|
|
801
|
+
throw new common_1.BadRequestException({
|
|
802
|
+
message: 'Email is already verified',
|
|
803
|
+
code: auth_constants_1.ERROR_CODES.EMAIL_ALREADY_VERIFIED,
|
|
804
|
+
});
|
|
662
805
|
}
|
|
663
806
|
// Generate OTP
|
|
664
807
|
const otp = (0, otp_1.generateOtp)();
|
|
@@ -682,6 +825,7 @@ let AuthService = class AuthService {
|
|
|
682
825
|
}
|
|
683
826
|
catch (error) {
|
|
684
827
|
this.debugLogger.logError(error, 'sendEmailVerification');
|
|
828
|
+
this.handleError(error, 'signup'); // Assuming email verification is part of signup flow or user profile management
|
|
685
829
|
throw error;
|
|
686
830
|
}
|
|
687
831
|
}
|
|
@@ -690,14 +834,23 @@ let AuthService = class AuthService {
|
|
|
690
834
|
try {
|
|
691
835
|
const user = request_context_1.RequestContext.currentUser();
|
|
692
836
|
if (!user) {
|
|
693
|
-
throw new common_1.UnauthorizedException(
|
|
837
|
+
throw new common_1.UnauthorizedException({
|
|
838
|
+
message: 'User not authenticated',
|
|
839
|
+
code: auth_constants_1.ERROR_CODES.UNAUTHORIZED,
|
|
840
|
+
});
|
|
694
841
|
}
|
|
695
842
|
const fullUser = await this.getUserWithRolesAndPermissions(user.id);
|
|
696
843
|
if (!fullUser.email) {
|
|
697
|
-
throw new common_1.BadRequestException(
|
|
844
|
+
throw new common_1.BadRequestException({
|
|
845
|
+
message: 'User does not have an email address',
|
|
846
|
+
code: auth_constants_1.ERROR_CODES.NO_EMAIL_ADDRESS,
|
|
847
|
+
});
|
|
698
848
|
}
|
|
699
849
|
if (fullUser.emailVerifiedAt) {
|
|
700
|
-
throw new common_1.BadRequestException(
|
|
850
|
+
throw new common_1.BadRequestException({
|
|
851
|
+
message: 'Email is already verified',
|
|
852
|
+
code: auth_constants_1.ERROR_CODES.EMAIL_ALREADY_VERIFIED,
|
|
853
|
+
});
|
|
701
854
|
}
|
|
702
855
|
// Find valid OTP
|
|
703
856
|
const validOtp = await this.otpRepository.findOne({
|
|
@@ -709,10 +862,16 @@ let AuthService = class AuthService {
|
|
|
709
862
|
}
|
|
710
863
|
});
|
|
711
864
|
if (!validOtp) {
|
|
712
|
-
throw new common_1.BadRequestException(
|
|
865
|
+
throw new common_1.BadRequestException({
|
|
866
|
+
message: 'Invalid verification code',
|
|
867
|
+
code: auth_constants_1.ERROR_CODES.VERIFICATION_CODE_INVALID,
|
|
868
|
+
});
|
|
713
869
|
}
|
|
714
870
|
if ((0, moment_1.default)(validOtp.expiresAt).isBefore(new Date())) {
|
|
715
|
-
throw new common_1.BadRequestException(
|
|
871
|
+
throw new common_1.BadRequestException({
|
|
872
|
+
message: 'Verification code has expired',
|
|
873
|
+
code: auth_constants_1.ERROR_CODES.VERIFICATION_CODE_EXPIRED,
|
|
874
|
+
});
|
|
716
875
|
}
|
|
717
876
|
// Mark OTP as used
|
|
718
877
|
validOtp.used = true;
|
|
@@ -731,11 +890,12 @@ let AuthService = class AuthService {
|
|
|
731
890
|
}
|
|
732
891
|
catch (error) {
|
|
733
892
|
this.debugLogger.logError(error, 'verifyEmail');
|
|
893
|
+
this.handleError(error, 'signup'); // Assuming email verification is part of signup flow or user profile management
|
|
734
894
|
throw error;
|
|
735
895
|
}
|
|
736
896
|
}
|
|
737
|
-
generateTokensPayload(session, otherPayload = {}) {
|
|
738
|
-
|
|
897
|
+
async generateTokensPayload(session, otherPayload = {}) {
|
|
898
|
+
let payload = {
|
|
739
899
|
id: session.userId,
|
|
740
900
|
sub: session.userId,
|
|
741
901
|
sessionId: session.id,
|
|
@@ -748,10 +908,29 @@ let AuthService = class AuthService {
|
|
|
748
908
|
isMfaVerified: session.data?.isMfaVerified,
|
|
749
909
|
...otherPayload,
|
|
750
910
|
};
|
|
911
|
+
// Apply custom token payload hook if configured
|
|
912
|
+
const config = this.authConfigService.getConfig();
|
|
913
|
+
if (config.session?.customizeTokenPayload) {
|
|
914
|
+
payload = await config.session.customizeTokenPayload(payload, session);
|
|
915
|
+
}
|
|
751
916
|
return payload;
|
|
752
917
|
}
|
|
918
|
+
/**
|
|
919
|
+
* Handle errors using the errorHandler hook if configured
|
|
920
|
+
*/
|
|
921
|
+
handleError(error, context) {
|
|
922
|
+
const config = this.authConfigService.getConfig();
|
|
923
|
+
if (config.errorHandler) {
|
|
924
|
+
// The hook can throw a new error or return a modified one
|
|
925
|
+
// If it returns, we throw that. If it throws, it propagates.
|
|
926
|
+
const result = config.errorHandler(error, context);
|
|
927
|
+
if (result) {
|
|
928
|
+
throw result;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
753
932
|
async generateTokensFromSession(session) {
|
|
754
|
-
const payload = this.generateTokensPayload(session);
|
|
933
|
+
const payload = await this.generateTokensPayload(session);
|
|
755
934
|
const tokens = await this.jwtService.generateTokens(payload);
|
|
756
935
|
return tokens;
|
|
757
936
|
}
|
|
@@ -770,5 +949,6 @@ exports.AuthService = AuthService = tslib_1.__decorate([
|
|
|
770
949
|
event_emitter_1.EventEmitter2,
|
|
771
950
|
tenant_service_1.TenantService,
|
|
772
951
|
debug_logger_service_1.DebugLoggerService,
|
|
773
|
-
auth_config_service_1.AuthConfigService
|
|
952
|
+
auth_config_service_1.AuthConfigService,
|
|
953
|
+
user_service_1.UserService])
|
|
774
954
|
], AuthService);
|