@flusys/nestjs-auth 1.0.0-beta → 1.0.0
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/README.md +590 -473
- package/cjs/config/auth.constants.js +12 -0
- package/cjs/controllers/authentication.controller.js +365 -24
- package/cjs/controllers/branch.controller.js +44 -1
- package/cjs/controllers/company-selection.controller.js +27 -20
- package/cjs/controllers/company.controller.js +44 -1
- package/cjs/controllers/user-permission.controller.js +82 -154
- package/cjs/controllers/user.controller.js +211 -7
- package/cjs/docs/auth-swagger.config.js +14 -7
- package/cjs/dtos/authentication.dto.js +114 -38
- package/cjs/dtos/index.js +0 -1
- package/cjs/dtos/user-permission.dto.js +28 -0
- package/cjs/dtos/user.dto.js +19 -4
- package/cjs/entities/index.js +5 -1
- package/cjs/entities/pending-registration.entity.js +125 -0
- package/cjs/entities/user-company-permission.entity.js +3 -9
- package/cjs/entities/user-token.entity.js +129 -0
- package/cjs/interceptors/clear-token.interceptor.js +10 -23
- package/cjs/interceptors/set-token.interceptor.js +15 -55
- package/cjs/interfaces/auth-email-provider.interface.js +45 -0
- package/cjs/interfaces/index.js +2 -0
- package/cjs/interfaces/user-enricher.interface.js +4 -0
- package/cjs/modules/auth.module.js +65 -143
- package/cjs/services/auth-config.service.js +25 -27
- package/cjs/services/auth-datasource.provider.js +13 -23
- package/cjs/services/auth-email.service.js +456 -0
- package/cjs/services/authentication.service.js +297 -349
- package/cjs/services/branch.service.js +9 -4
- package/cjs/services/company-selection-session.service.js +1 -1
- package/cjs/services/index.js +1 -0
- package/cjs/services/user-permission.service.js +43 -73
- package/cjs/services/user.service.js +184 -34
- package/cjs/strategies/jwt.strategy.js +44 -44
- package/cjs/validators/password.validator.js +45 -0
- package/config/auth.constants.d.ts +3 -0
- package/controllers/authentication.controller.d.ts +16 -10
- package/controllers/company-selection.controller.d.ts +6 -2
- package/controllers/user-permission.controller.d.ts +5 -4
- package/controllers/user.controller.d.ts +33 -0
- package/dtos/authentication.dto.d.ts +20 -6
- package/dtos/company-branch.dto.d.ts +0 -1
- package/dtos/company.dto.d.ts +0 -1
- package/dtos/index.d.ts +0 -1
- package/dtos/user-permission.dto.d.ts +4 -0
- package/dtos/user.dto.d.ts +1 -2
- package/entities/index.d.ts +7 -3
- package/entities/pending-registration.entity.d.ts +17 -0
- package/entities/user-company-permission.entity.d.ts +1 -3
- package/entities/user-token.entity.d.ts +15 -0
- package/fesm/config/auth.constants.js +6 -2
- package/fesm/controllers/authentication.controller.js +368 -27
- package/fesm/controllers/branch.controller.js +45 -2
- package/fesm/controllers/company-selection.controller.js +28 -21
- package/fesm/controllers/company.controller.js +45 -2
- package/fesm/controllers/user-permission.controller.js +84 -156
- package/fesm/controllers/user.controller.js +214 -10
- package/fesm/docs/auth-swagger.config.js +14 -7
- package/fesm/dtos/authentication.dto.js +101 -39
- package/fesm/dtos/index.js +0 -1
- package/fesm/dtos/user-permission.dto.js +28 -0
- package/fesm/dtos/user.dto.js +20 -5
- package/fesm/entities/index.js +7 -1
- package/fesm/entities/pending-registration.entity.js +115 -0
- package/fesm/entities/user-company-permission.entity.js +3 -9
- package/fesm/entities/user-token.entity.js +113 -0
- package/fesm/interceptors/clear-token.interceptor.js +9 -22
- package/fesm/interceptors/set-token.interceptor.js +14 -54
- package/fesm/interfaces/auth-email-provider.interface.js +38 -0
- package/fesm/interfaces/authentication.interface.js +1 -1
- package/fesm/interfaces/index.js +2 -0
- package/fesm/interfaces/user-enricher.interface.js +26 -0
- package/fesm/modules/auth.module.js +67 -145
- package/fesm/services/auth-config.service.js +26 -28
- package/fesm/services/auth-datasource.provider.js +14 -24
- package/fesm/services/auth-email.service.js +405 -0
- package/fesm/services/authentication.service.js +297 -349
- package/fesm/services/branch.service.js +9 -4
- package/fesm/services/company-selection-session.service.js +1 -1
- package/fesm/services/index.js +1 -0
- package/fesm/services/user-permission.service.js +44 -74
- package/fesm/services/user.service.js +186 -36
- package/fesm/strategies/jwt.strategy.js +44 -44
- package/fesm/validators/password.validator.js +48 -0
- package/interceptors/clear-token.interceptor.d.ts +0 -1
- package/interceptors/set-token.interceptor.d.ts +1 -1
- package/interfaces/auth-email-provider.interface.d.ts +6 -0
- package/interfaces/auth-module-options.interface.d.ts +4 -1
- package/interfaces/authentication.interface.d.ts +13 -3
- package/interfaces/index.d.ts +2 -0
- package/interfaces/user-enricher.interface.d.ts +64 -0
- package/interfaces/user.interface.d.ts +1 -0
- package/modules/auth.module.d.ts +6 -3
- package/package.json +4 -4
- package/services/auth-config.service.d.ts +7 -8
- package/services/auth-datasource.provider.d.ts +2 -4
- package/services/auth-email.service.d.ts +54 -0
- package/services/authentication.service.d.ts +27 -16
- package/services/company-selection-session.service.d.ts +1 -1
- package/services/index.d.ts +1 -0
- package/services/user-permission.service.d.ts +6 -9
- package/services/user.service.d.ts +19 -3
- package/strategies/jwt.strategy.d.ts +4 -1
- package/validators/password.validator.d.ts +10 -0
- package/cjs/dtos/user-company-permission.dto.js +0 -110
- package/dtos/user-company-permission.dto.d.ts +0 -10
- package/fesm/dtos/user-company-permission.dto.js +0 -98
|
@@ -16,14 +16,26 @@ _export(exports, {
|
|
|
16
16
|
get BCRYPT_SALT_ROUNDS () {
|
|
17
17
|
return BCRYPT_SALT_ROUNDS;
|
|
18
18
|
},
|
|
19
|
+
get DEFAULT_COOKIE_NAME () {
|
|
20
|
+
return DEFAULT_COOKIE_NAME;
|
|
21
|
+
},
|
|
22
|
+
get MAX_COOKIE_BYTES () {
|
|
23
|
+
return MAX_COOKIE_BYTES;
|
|
24
|
+
},
|
|
19
25
|
get SESSION_CACHE_PREFIX () {
|
|
20
26
|
return SESSION_CACHE_PREFIX;
|
|
21
27
|
},
|
|
22
28
|
get TOKEN_REVOKED_PREFIX () {
|
|
23
29
|
return TOKEN_REVOKED_PREFIX;
|
|
30
|
+
},
|
|
31
|
+
get USER_ENRICHER () {
|
|
32
|
+
return USER_ENRICHER;
|
|
24
33
|
}
|
|
25
34
|
});
|
|
26
35
|
const AUTH_MODULE_OPTIONS = 'AUTH_MODULE_OPTIONS';
|
|
36
|
+
const USER_ENRICHER = 'USER_ENRICHER';
|
|
27
37
|
const BCRYPT_SALT_ROUNDS = 12;
|
|
38
|
+
const DEFAULT_COOKIE_NAME = 'fsn_refresh_token';
|
|
39
|
+
const MAX_COOKIE_BYTES = 3500;
|
|
28
40
|
const SESSION_CACHE_PREFIX = 'auth:session';
|
|
29
41
|
const TOKEN_REVOKED_PREFIX = 'auth:revoked';
|
|
@@ -9,15 +9,19 @@ Object.defineProperty(exports, "AuthenticationController", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _decorators = require("@flusys/nestjs-shared/decorators");
|
|
12
|
+
const _dtos = require("@flusys/nestjs-shared/dtos");
|
|
12
13
|
const _guards = require("@flusys/nestjs-shared/guards");
|
|
13
14
|
const _interfaces = require("@flusys/nestjs-shared/interfaces");
|
|
14
15
|
const _common = require("@nestjs/common");
|
|
15
16
|
const _swagger = require("@nestjs/swagger");
|
|
17
|
+
const _throttler = require("@nestjs/throttler");
|
|
16
18
|
const _express = require("express");
|
|
19
|
+
const _config = require("../config");
|
|
17
20
|
const _authenticationdto = require("../dtos/authentication.dto");
|
|
18
21
|
const _cleartokeninterceptor = require("../interceptors/clear-token.interceptor");
|
|
19
22
|
const _settokeninterceptor = require("../interceptors/set-token.interceptor");
|
|
20
23
|
const _authconfigservice = require("../services/auth-config.service");
|
|
24
|
+
const _authemailservice = require("../services/auth-email.service");
|
|
21
25
|
const _authenticationservice = require("../services/authentication.service");
|
|
22
26
|
function _define_property(obj, key, value) {
|
|
23
27
|
if (key in obj) {
|
|
@@ -47,24 +51,41 @@ function _ts_param(paramIndex, decorator) {
|
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
53
|
let AuthenticationController = class AuthenticationController {
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
buildAuthUrl(req, path) {
|
|
55
|
+
const frontendUrl = this.authConfig?.getFrontendUrl();
|
|
56
|
+
return frontendUrl ? `${frontendUrl}${path}` : `${req.protocol}://${req.get('host')}${path}`;
|
|
57
|
+
}
|
|
58
|
+
get emailService() {
|
|
59
|
+
if (!this.authEmailService) {
|
|
60
|
+
throw new Error('Email service is not configured');
|
|
61
|
+
}
|
|
62
|
+
return this.authEmailService;
|
|
63
|
+
}
|
|
64
|
+
get isEmailEnabled() {
|
|
65
|
+
return !!this.authEmailService;
|
|
66
|
+
}
|
|
67
|
+
async login(loginDto) {
|
|
52
68
|
const result = await this.authService.login(loginDto.email, loginDto.password);
|
|
69
|
+
if ('requiresEmailVerification' in result) {
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
53
72
|
if ('requiresSelection' in result) {
|
|
54
73
|
return result;
|
|
55
74
|
}
|
|
56
75
|
return result;
|
|
57
76
|
}
|
|
58
|
-
/** Register new user. If company feature enabled, can join/create company. */ async register(registrationDto) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
companyFeatureEnabled: this.authConfig?.isCompanyFeatureEnabled() ?? false
|
|
63
|
-
};
|
|
77
|
+
/** Register new user. If company feature enabled, can join/create company. */ async register(req, registrationDto) {
|
|
78
|
+
const verifyUrlBase = this.buildAuthUrl(req, '/auth/verify-email');
|
|
79
|
+
const result = await this.authService.register(registrationDto, verifyUrlBase);
|
|
80
|
+
return result;
|
|
64
81
|
}
|
|
65
|
-
/**
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Refresh access token.
|
|
84
|
+
* - **Browser**: Prefers HTTP-only cookie, falls back to body if cookie missing.
|
|
85
|
+
* - **API/Mobile**: Must send `refreshToken` in request body. Set header `x-client-type: mobile` or `x-client-type: api`.
|
|
86
|
+
*/ async refreshToken(req, refreshTokenDto) {
|
|
87
|
+
const cookieName = this.authConfig?.getRefreshTokenCookieName() ?? _config.DEFAULT_COOKIE_NAME;
|
|
88
|
+
// Always check cookie first, then body - handles Browser, SSR, and Mobile/API
|
|
68
89
|
const refreshToken = req.cookies?.[cookieName] || refreshTokenDto.refreshToken;
|
|
69
90
|
if (!refreshToken) {
|
|
70
91
|
throw new _common.UnauthorizedException('Refresh token is required');
|
|
@@ -77,26 +98,78 @@ let AuthenticationController = class AuthenticationController {
|
|
|
77
98
|
/** Logout - Clears refresh token cookie for browsers */ async logout(userId) {
|
|
78
99
|
await this.authService.logout(userId);
|
|
79
100
|
return {
|
|
101
|
+
success: true,
|
|
80
102
|
message: 'Logged out successfully'
|
|
81
103
|
};
|
|
82
104
|
}
|
|
83
|
-
|
|
105
|
+
async changePassword(userId, dto) {
|
|
84
106
|
await this.authService.changePassword(userId, dto.currentPassword, dto.newPassword);
|
|
85
107
|
return {
|
|
108
|
+
success: true,
|
|
86
109
|
message: 'Password changed successfully'
|
|
87
110
|
};
|
|
88
111
|
}
|
|
89
|
-
|
|
90
|
-
|
|
112
|
+
async forgotPassword(req, dto) {
|
|
113
|
+
if (!this.isEmailEnabled) {
|
|
114
|
+
return {
|
|
115
|
+
success: false,
|
|
116
|
+
message: 'Email service is not configured'
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return this.emailService.forgotPassword(dto.email, this.buildAuthUrl(req, '/auth/reset-password'));
|
|
120
|
+
}
|
|
121
|
+
async resetPassword(dto) {
|
|
122
|
+
if (!this.isEmailEnabled) {
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
message: 'Email service is not configured'
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return this.emailService.resetPassword(dto.token, dto.newPassword);
|
|
129
|
+
}
|
|
130
|
+
async resendVerification(req, dto) {
|
|
131
|
+
if (!this.isEmailEnabled) {
|
|
132
|
+
return {
|
|
133
|
+
success: false,
|
|
134
|
+
message: 'Email service is not configured'
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return this.emailService.resendVerificationEmail(dto.email, this.buildAuthUrl(req, '/auth/verify-email'));
|
|
138
|
+
}
|
|
139
|
+
/** Verify email - Verify email using token. Handles both pending registration and existing user verification. */ async verifyEmail(dto) {
|
|
140
|
+
if (!this.isEmailEnabled) {
|
|
141
|
+
return {
|
|
142
|
+
success: false,
|
|
143
|
+
message: 'Email service is not configured'
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const result = await this.emailService.verifyEmail(dto.token);
|
|
147
|
+
if (result.type === 'pending') {
|
|
148
|
+
return this.authService.createUserFromPendingRegistration(result.pending);
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
success: true,
|
|
152
|
+
message: result.message
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
constructor(authService, authConfig, authEmailService){
|
|
91
156
|
_define_property(this, "authService", void 0);
|
|
92
157
|
_define_property(this, "authConfig", void 0);
|
|
158
|
+
_define_property(this, "authEmailService", void 0);
|
|
93
159
|
this.authService = authService;
|
|
94
160
|
this.authConfig = authConfig;
|
|
161
|
+
this.authEmailService = authEmailService;
|
|
95
162
|
}
|
|
96
163
|
};
|
|
97
164
|
_ts_decorate([
|
|
98
165
|
(0, _common.Post)('login'),
|
|
99
166
|
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
167
|
+
(0, _throttler.Throttle)({
|
|
168
|
+
default: {
|
|
169
|
+
limit: 5,
|
|
170
|
+
ttl: 60000
|
|
171
|
+
}
|
|
172
|
+
}),
|
|
100
173
|
(0, _common.UseInterceptors)(_settokeninterceptor.SetToken),
|
|
101
174
|
(0, _swagger.ApiOperation)({
|
|
102
175
|
summary: 'User login'
|
|
@@ -104,13 +177,102 @@ _ts_decorate([
|
|
|
104
177
|
(0, _swagger.ApiBody)({
|
|
105
178
|
type: _authenticationdto.LoginDto
|
|
106
179
|
}),
|
|
180
|
+
(0, _swagger.ApiExtraModels)(_authenticationdto.LoginResponseDto, _authenticationdto.CompanySelectionResponseDto, _authenticationdto.LoginResponseRequiresEmailVerificationDto),
|
|
107
181
|
(0, _swagger.ApiResponse)({
|
|
108
182
|
status: 200,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
183
|
+
description: 'Login successful, requires company selection, or requires email verification',
|
|
184
|
+
content: {
|
|
185
|
+
'application/json': {
|
|
186
|
+
schema: {
|
|
187
|
+
oneOf: [
|
|
188
|
+
{
|
|
189
|
+
$ref: (0, _swagger.getSchemaPath)(_authenticationdto.LoginResponseDto)
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
$ref: (0, _swagger.getSchemaPath)(_authenticationdto.CompanySelectionResponseDto)
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
$ref: (0, _swagger.getSchemaPath)(_authenticationdto.LoginResponseRequiresEmailVerificationDto)
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
examples: {
|
|
200
|
+
loginSuccess: {
|
|
201
|
+
summary: 'Login Success',
|
|
202
|
+
description: 'Successful login with tokens (company/branch included when company feature enabled)',
|
|
203
|
+
value: {
|
|
204
|
+
accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
205
|
+
refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
206
|
+
user: {
|
|
207
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
208
|
+
email: 'john@example.com',
|
|
209
|
+
name: 'John Doe'
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
loginSuccessWithCompany: {
|
|
214
|
+
summary: 'Login Success (Company Feature)',
|
|
215
|
+
description: 'Login with company/branch - only when company feature is enabled',
|
|
216
|
+
value: {
|
|
217
|
+
accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
218
|
+
refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
219
|
+
user: {
|
|
220
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
221
|
+
email: 'john@example.com',
|
|
222
|
+
name: 'John Doe'
|
|
223
|
+
},
|
|
224
|
+
company: {
|
|
225
|
+
id: '550e8400-e29b-41d4-a716-446655440001',
|
|
226
|
+
name: 'Acme Corporation',
|
|
227
|
+
slug: 'acme-corp'
|
|
228
|
+
},
|
|
229
|
+
branch: {
|
|
230
|
+
id: '550e8400-e29b-41d4-a716-446655440002',
|
|
231
|
+
name: 'Main Branch',
|
|
232
|
+
slug: 'main-branch'
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
companySelection: {
|
|
237
|
+
summary: 'Company Selection Required (Company Feature)',
|
|
238
|
+
description: 'User has multiple companies/branches - only when company feature is enabled',
|
|
239
|
+
value: {
|
|
240
|
+
requiresSelection: true,
|
|
241
|
+
sessionId: 'sess_abc123def456',
|
|
242
|
+
expiresAt: '2024-12-18T15:30:00.000Z',
|
|
243
|
+
user: {
|
|
244
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
245
|
+
email: 'john@example.com',
|
|
246
|
+
name: 'John Doe'
|
|
247
|
+
},
|
|
248
|
+
companies: [
|
|
249
|
+
{
|
|
250
|
+
id: '550e8400-e29b-41d4-a716-446655440001',
|
|
251
|
+
name: 'Company A',
|
|
252
|
+
slug: 'company-a',
|
|
253
|
+
branches: [
|
|
254
|
+
{
|
|
255
|
+
id: '550e8400-e29b-41d4-a716-446655440010',
|
|
256
|
+
name: 'Branch 1',
|
|
257
|
+
slug: 'branch-1'
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
emailVerification: {
|
|
265
|
+
summary: 'Email Verification Required',
|
|
266
|
+
description: 'User must verify email before logging in',
|
|
267
|
+
value: {
|
|
268
|
+
requiresEmailVerification: true,
|
|
269
|
+
email: 'john@example.com',
|
|
270
|
+
message: 'Please verify your email address before logging in.'
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
114
276
|
}),
|
|
115
277
|
_ts_param(0, (0, _common.Body)()),
|
|
116
278
|
_ts_metadata("design:type", Function),
|
|
@@ -122,6 +284,12 @@ _ts_decorate([
|
|
|
122
284
|
_ts_decorate([
|
|
123
285
|
(0, _common.Post)('register'),
|
|
124
286
|
(0, _common.HttpCode)(_common.HttpStatus.CREATED),
|
|
287
|
+
(0, _throttler.Throttle)({
|
|
288
|
+
default: {
|
|
289
|
+
limit: 3,
|
|
290
|
+
ttl: 60000
|
|
291
|
+
}
|
|
292
|
+
}),
|
|
125
293
|
(0, _common.UseInterceptors)(_settokeninterceptor.SetToken),
|
|
126
294
|
(0, _swagger.ApiOperation)({
|
|
127
295
|
summary: 'Register new user'
|
|
@@ -133,9 +301,11 @@ _ts_decorate([
|
|
|
133
301
|
status: 201,
|
|
134
302
|
type: _authenticationdto.RegistrationResponseDto
|
|
135
303
|
}),
|
|
136
|
-
_ts_param(0, (0, _common.
|
|
304
|
+
_ts_param(0, (0, _common.Req)()),
|
|
305
|
+
_ts_param(1, (0, _common.Body)()),
|
|
137
306
|
_ts_metadata("design:type", Function),
|
|
138
307
|
_ts_metadata("design:paramtypes", [
|
|
308
|
+
typeof _express.Request === "undefined" ? Object : _express.Request,
|
|
139
309
|
typeof _authenticationdto.RegistrationDto === "undefined" ? Object : _authenticationdto.RegistrationDto
|
|
140
310
|
]),
|
|
141
311
|
_ts_metadata("design:returntype", Promise)
|
|
@@ -143,11 +313,50 @@ _ts_decorate([
|
|
|
143
313
|
_ts_decorate([
|
|
144
314
|
(0, _common.Post)('refresh'),
|
|
145
315
|
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
316
|
+
(0, _throttler.Throttle)({
|
|
317
|
+
default: {
|
|
318
|
+
limit: 30,
|
|
319
|
+
ttl: 60000
|
|
320
|
+
}
|
|
321
|
+
}),
|
|
146
322
|
(0, _swagger.ApiOperation)({
|
|
147
|
-
summary: 'Refresh access token'
|
|
323
|
+
summary: 'Refresh access token',
|
|
324
|
+
description: `
|
|
325
|
+
**Browser clients**: Refresh token is read from HTTP-only cookie (automatically set on login/register).
|
|
326
|
+
Falls back to request body if cookie is not available.
|
|
327
|
+
|
|
328
|
+
**API/Mobile clients**: Must send \`refreshToken\` in request body.
|
|
329
|
+
Set header \`x-client-type: mobile\` or \`x-client-type: api\` to identify as non-browser client.
|
|
330
|
+
|
|
331
|
+
**Client detection**: Uses \`x-client-type\` header first, then falls back to User-Agent detection.
|
|
332
|
+
`
|
|
333
|
+
}),
|
|
334
|
+
(0, _swagger.ApiHeader)({
|
|
335
|
+
name: 'x-client-type',
|
|
336
|
+
required: false,
|
|
337
|
+
description: 'Client type: "browser"/"web" for cookie-based auth, "mobile"/"api" for body-based auth',
|
|
338
|
+
example: 'mobile'
|
|
148
339
|
}),
|
|
149
340
|
(0, _swagger.ApiBody)({
|
|
150
|
-
type: _authenticationdto.RefreshTokenDto
|
|
341
|
+
type: _authenticationdto.RefreshTokenDto,
|
|
342
|
+
description: 'Required for API/Mobile clients. Browser clients prefer HTTP-only cookie with body fallback.'
|
|
343
|
+
}),
|
|
344
|
+
(0, _swagger.ApiResponse)({
|
|
345
|
+
status: 200,
|
|
346
|
+
description: 'New access token',
|
|
347
|
+
schema: {
|
|
348
|
+
type: 'object',
|
|
349
|
+
properties: {
|
|
350
|
+
accessToken: {
|
|
351
|
+
type: 'string',
|
|
352
|
+
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}),
|
|
357
|
+
(0, _swagger.ApiResponse)({
|
|
358
|
+
status: 401,
|
|
359
|
+
description: 'Invalid or missing refresh token'
|
|
151
360
|
}),
|
|
152
361
|
_ts_param(0, (0, _common.Req)()),
|
|
153
362
|
_ts_param(1, (0, _common.Body)()),
|
|
@@ -160,7 +369,8 @@ _ts_decorate([
|
|
|
160
369
|
], AuthenticationController.prototype, "refreshToken", null);
|
|
161
370
|
_ts_decorate([
|
|
162
371
|
(0, _common.UseGuards)(_guards.JwtAuthGuard),
|
|
163
|
-
(0, _common.
|
|
372
|
+
(0, _common.Post)('me'),
|
|
373
|
+
(0, _throttler.SkipThrottle)(),
|
|
164
374
|
(0, _swagger.ApiBearerAuth)(),
|
|
165
375
|
(0, _swagger.ApiOperation)({
|
|
166
376
|
summary: 'Get current user info'
|
|
@@ -180,11 +390,16 @@ _ts_decorate([
|
|
|
180
390
|
(0, _common.UseGuards)(_guards.JwtAuthGuard),
|
|
181
391
|
(0, _common.Post)('logout'),
|
|
182
392
|
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
393
|
+
(0, _throttler.SkipThrottle)(),
|
|
183
394
|
(0, _common.UseInterceptors)(_cleartokeninterceptor.ClearToken),
|
|
184
395
|
(0, _swagger.ApiBearerAuth)(),
|
|
185
396
|
(0, _swagger.ApiOperation)({
|
|
186
397
|
summary: 'Logout user'
|
|
187
398
|
}),
|
|
399
|
+
(0, _swagger.ApiResponse)({
|
|
400
|
+
status: 200,
|
|
401
|
+
type: _dtos.MessageResponseDto
|
|
402
|
+
}),
|
|
188
403
|
_ts_param(0, (0, _decorators.CurrentUser)('id')),
|
|
189
404
|
_ts_metadata("design:type", Function),
|
|
190
405
|
_ts_metadata("design:paramtypes", [
|
|
@@ -196,6 +411,12 @@ _ts_decorate([
|
|
|
196
411
|
(0, _common.UseGuards)(_guards.JwtAuthGuard),
|
|
197
412
|
(0, _common.Post)('change-password'),
|
|
198
413
|
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
414
|
+
(0, _throttler.Throttle)({
|
|
415
|
+
default: {
|
|
416
|
+
limit: 5,
|
|
417
|
+
ttl: 60000
|
|
418
|
+
}
|
|
419
|
+
}),
|
|
199
420
|
(0, _swagger.ApiBearerAuth)(),
|
|
200
421
|
(0, _swagger.ApiOperation)({
|
|
201
422
|
summary: 'Change password'
|
|
@@ -203,6 +424,10 @@ _ts_decorate([
|
|
|
203
424
|
(0, _swagger.ApiBody)({
|
|
204
425
|
type: _authenticationdto.ChangePasswordDto
|
|
205
426
|
}),
|
|
427
|
+
(0, _swagger.ApiResponse)({
|
|
428
|
+
status: 200,
|
|
429
|
+
type: _dtos.MessageResponseDto
|
|
430
|
+
}),
|
|
206
431
|
_ts_param(0, (0, _decorators.CurrentUser)('id')),
|
|
207
432
|
_ts_param(1, (0, _common.Body)()),
|
|
208
433
|
_ts_metadata("design:type", Function),
|
|
@@ -212,15 +437,131 @@ _ts_decorate([
|
|
|
212
437
|
]),
|
|
213
438
|
_ts_metadata("design:returntype", Promise)
|
|
214
439
|
], AuthenticationController.prototype, "changePassword", null);
|
|
440
|
+
_ts_decorate([
|
|
441
|
+
(0, _common.Post)('forgot-password'),
|
|
442
|
+
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
443
|
+
(0, _throttler.Throttle)({
|
|
444
|
+
default: {
|
|
445
|
+
limit: 3,
|
|
446
|
+
ttl: 300000
|
|
447
|
+
}
|
|
448
|
+
}),
|
|
449
|
+
(0, _swagger.ApiOperation)({
|
|
450
|
+
summary: 'Request password reset email'
|
|
451
|
+
}),
|
|
452
|
+
(0, _swagger.ApiBody)({
|
|
453
|
+
type: _authenticationdto.ForgotPasswordDto
|
|
454
|
+
}),
|
|
455
|
+
(0, _swagger.ApiResponse)({
|
|
456
|
+
status: 200,
|
|
457
|
+
type: _dtos.MessageResponseDto
|
|
458
|
+
}),
|
|
459
|
+
_ts_param(0, (0, _common.Req)()),
|
|
460
|
+
_ts_param(1, (0, _common.Body)()),
|
|
461
|
+
_ts_metadata("design:type", Function),
|
|
462
|
+
_ts_metadata("design:paramtypes", [
|
|
463
|
+
typeof _express.Request === "undefined" ? Object : _express.Request,
|
|
464
|
+
typeof _authenticationdto.ForgotPasswordDto === "undefined" ? Object : _authenticationdto.ForgotPasswordDto
|
|
465
|
+
]),
|
|
466
|
+
_ts_metadata("design:returntype", Promise)
|
|
467
|
+
], AuthenticationController.prototype, "forgotPassword", null);
|
|
468
|
+
_ts_decorate([
|
|
469
|
+
(0, _common.Post)('reset-password'),
|
|
470
|
+
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
471
|
+
(0, _throttler.Throttle)({
|
|
472
|
+
default: {
|
|
473
|
+
limit: 5,
|
|
474
|
+
ttl: 900000
|
|
475
|
+
}
|
|
476
|
+
}),
|
|
477
|
+
(0, _swagger.ApiOperation)({
|
|
478
|
+
summary: 'Reset password using token'
|
|
479
|
+
}),
|
|
480
|
+
(0, _swagger.ApiBody)({
|
|
481
|
+
type: _authenticationdto.ResetPasswordDto
|
|
482
|
+
}),
|
|
483
|
+
(0, _swagger.ApiResponse)({
|
|
484
|
+
status: 200,
|
|
485
|
+
type: _dtos.MessageResponseDto
|
|
486
|
+
}),
|
|
487
|
+
_ts_param(0, (0, _common.Body)()),
|
|
488
|
+
_ts_metadata("design:type", Function),
|
|
489
|
+
_ts_metadata("design:paramtypes", [
|
|
490
|
+
typeof _authenticationdto.ResetPasswordDto === "undefined" ? Object : _authenticationdto.ResetPasswordDto
|
|
491
|
+
]),
|
|
492
|
+
_ts_metadata("design:returntype", Promise)
|
|
493
|
+
], AuthenticationController.prototype, "resetPassword", null);
|
|
494
|
+
_ts_decorate([
|
|
495
|
+
(0, _common.Post)('resend-verification'),
|
|
496
|
+
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
497
|
+
(0, _throttler.Throttle)({
|
|
498
|
+
default: {
|
|
499
|
+
limit: 3,
|
|
500
|
+
ttl: 300000
|
|
501
|
+
}
|
|
502
|
+
}),
|
|
503
|
+
(0, _swagger.ApiOperation)({
|
|
504
|
+
summary: 'Resend email verification link'
|
|
505
|
+
}),
|
|
506
|
+
(0, _swagger.ApiBody)({
|
|
507
|
+
type: _authenticationdto.ResendVerificationDto
|
|
508
|
+
}),
|
|
509
|
+
(0, _swagger.ApiResponse)({
|
|
510
|
+
status: 200,
|
|
511
|
+
type: _dtos.MessageResponseDto
|
|
512
|
+
}),
|
|
513
|
+
_ts_param(0, (0, _common.Req)()),
|
|
514
|
+
_ts_param(1, (0, _common.Body)()),
|
|
515
|
+
_ts_metadata("design:type", Function),
|
|
516
|
+
_ts_metadata("design:paramtypes", [
|
|
517
|
+
typeof _express.Request === "undefined" ? Object : _express.Request,
|
|
518
|
+
typeof _authenticationdto.ResendVerificationDto === "undefined" ? Object : _authenticationdto.ResendVerificationDto
|
|
519
|
+
]),
|
|
520
|
+
_ts_metadata("design:returntype", Promise)
|
|
521
|
+
], AuthenticationController.prototype, "resendVerification", null);
|
|
522
|
+
_ts_decorate([
|
|
523
|
+
(0, _common.Post)('verify-email'),
|
|
524
|
+
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
525
|
+
(0, _throttler.Throttle)({
|
|
526
|
+
default: {
|
|
527
|
+
limit: 10,
|
|
528
|
+
ttl: 60000
|
|
529
|
+
}
|
|
530
|
+
}),
|
|
531
|
+
(0, _common.UseInterceptors)(_settokeninterceptor.SetToken),
|
|
532
|
+
(0, _swagger.ApiOperation)({
|
|
533
|
+
summary: 'Verify email using token'
|
|
534
|
+
}),
|
|
535
|
+
(0, _swagger.ApiBody)({
|
|
536
|
+
type: _authenticationdto.VerifyEmailDto
|
|
537
|
+
}),
|
|
538
|
+
(0, _swagger.ApiResponse)({
|
|
539
|
+
status: 200,
|
|
540
|
+
type: _dtos.MessageResponseDto
|
|
541
|
+
}),
|
|
542
|
+
(0, _swagger.ApiResponse)({
|
|
543
|
+
status: 200,
|
|
544
|
+
type: _authenticationdto.RegistrationResponseDto
|
|
545
|
+
}),
|
|
546
|
+
_ts_param(0, (0, _common.Body)()),
|
|
547
|
+
_ts_metadata("design:type", Function),
|
|
548
|
+
_ts_metadata("design:paramtypes", [
|
|
549
|
+
typeof _authenticationdto.VerifyEmailDto === "undefined" ? Object : _authenticationdto.VerifyEmailDto
|
|
550
|
+
]),
|
|
551
|
+
_ts_metadata("design:returntype", Promise)
|
|
552
|
+
], AuthenticationController.prototype, "verifyEmail", null);
|
|
215
553
|
AuthenticationController = _ts_decorate([
|
|
216
554
|
(0, _swagger.ApiTags)('Authentication'),
|
|
217
555
|
(0, _common.Controller)('auth'),
|
|
218
556
|
_ts_param(0, (0, _common.Inject)(_authenticationservice.AuthenticationService)),
|
|
219
557
|
_ts_param(1, (0, _common.Optional)()),
|
|
220
558
|
_ts_param(1, (0, _common.Inject)(_authconfigservice.AuthConfigService)),
|
|
559
|
+
_ts_param(2, (0, _common.Optional)()),
|
|
560
|
+
_ts_param(2, (0, _common.Inject)(_authemailservice.AuthEmailService)),
|
|
221
561
|
_ts_metadata("design:type", Function),
|
|
222
562
|
_ts_metadata("design:paramtypes", [
|
|
223
563
|
typeof _authenticationservice.AuthenticationService === "undefined" ? Object : _authenticationservice.AuthenticationService,
|
|
224
|
-
typeof _authconfigservice.AuthConfigService === "undefined" ? Object : _authconfigservice.AuthConfigService
|
|
564
|
+
typeof _authconfigservice.AuthConfigService === "undefined" ? Object : _authconfigservice.AuthConfigService,
|
|
565
|
+
typeof _authemailservice.AuthEmailService === "undefined" ? Object : _authemailservice.AuthEmailService
|
|
225
566
|
])
|
|
226
567
|
], AuthenticationController);
|
|
@@ -41,7 +41,50 @@ function _ts_param(paramIndex, decorator) {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
let BranchController = class BranchController extends (0, _classes.createApiController)(_companybranchdto.CreateCompanyBranchDto, _companybranchdto.UpdateCompanyBranchDto, _companybranchdto.CompanyBranchResponseDto, {
|
|
44
|
-
security:
|
|
44
|
+
security: {
|
|
45
|
+
insert: {
|
|
46
|
+
level: 'permission',
|
|
47
|
+
permissions: [
|
|
48
|
+
_classes.BRANCH_PERMISSIONS.CREATE
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
insertMany: {
|
|
52
|
+
level: 'permission',
|
|
53
|
+
permissions: [
|
|
54
|
+
_classes.BRANCH_PERMISSIONS.CREATE
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
getById: {
|
|
58
|
+
level: 'permission',
|
|
59
|
+
permissions: [
|
|
60
|
+
_classes.BRANCH_PERMISSIONS.READ
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
getAll: {
|
|
64
|
+
level: 'permission',
|
|
65
|
+
permissions: [
|
|
66
|
+
_classes.BRANCH_PERMISSIONS.READ
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
update: {
|
|
70
|
+
level: 'permission',
|
|
71
|
+
permissions: [
|
|
72
|
+
_classes.BRANCH_PERMISSIONS.UPDATE
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
updateMany: {
|
|
76
|
+
level: 'permission',
|
|
77
|
+
permissions: [
|
|
78
|
+
_classes.BRANCH_PERMISSIONS.UPDATE
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
delete: {
|
|
82
|
+
level: 'permission',
|
|
83
|
+
permissions: [
|
|
84
|
+
_classes.BRANCH_PERMISSIONS.DELETE
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
45
88
|
}) {
|
|
46
89
|
constructor(branchService){
|
|
47
90
|
super(branchService), _define_property(this, "branchService", void 0), this.branchService = branchService;
|
|
@@ -43,35 +43,28 @@ function _ts_param(paramIndex, decorator) {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
let CompanySelectionController = class CompanySelectionController {
|
|
46
|
-
|
|
47
|
-
* Select Company & Branch
|
|
48
|
-
* Used after login when user needs to select company and branch
|
|
49
|
-
*/ async select(dto) {
|
|
46
|
+
async select(dto) {
|
|
50
47
|
return this.authService.select(dto.sessionId, dto.companyId, dto.branchId);
|
|
51
48
|
}
|
|
52
|
-
|
|
53
|
-
* Switch Company/Branch
|
|
54
|
-
* Used to switch company/branch after already logged in
|
|
55
|
-
*/ async switchCompany(userId, dto) {
|
|
49
|
+
async switchCompany(userId, dto) {
|
|
56
50
|
return this.authService.switchCompany(userId, dto.companyId, dto.branchId);
|
|
57
51
|
}
|
|
58
|
-
|
|
59
|
-
* Get user's companies
|
|
60
|
-
*/ async getUserCompanies(userId) {
|
|
52
|
+
async getUserCompanies(userId) {
|
|
61
53
|
const companies = await this.authService.getUserCompanies(userId);
|
|
62
54
|
return {
|
|
63
|
-
|
|
55
|
+
success: true,
|
|
56
|
+
message: 'User companies retrieved successfully',
|
|
57
|
+
data: companies
|
|
64
58
|
};
|
|
65
59
|
}
|
|
66
|
-
|
|
67
|
-
* Get branches for a specific company
|
|
68
|
-
*/ async getUserBranches(userId, companyId) {
|
|
60
|
+
async getUserBranches(userId, companyId) {
|
|
69
61
|
const branches = await this.authService.getUserBranches(userId, companyId);
|
|
70
62
|
return {
|
|
71
|
-
|
|
63
|
+
success: true,
|
|
64
|
+
message: 'Company branches retrieved successfully',
|
|
65
|
+
data: branches
|
|
72
66
|
};
|
|
73
67
|
}
|
|
74
|
-
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
75
68
|
constructor(authService){
|
|
76
69
|
_define_property(this, "authService", void 0);
|
|
77
70
|
this.authService = authService;
|
|
@@ -127,7 +120,8 @@ _ts_decorate([
|
|
|
127
120
|
], CompanySelectionController.prototype, "switchCompany", null);
|
|
128
121
|
_ts_decorate([
|
|
129
122
|
(0, _common.UseGuards)(_guards.JwtAuthGuard),
|
|
130
|
-
(0, _common.
|
|
123
|
+
(0, _common.Post)('get-companies'),
|
|
124
|
+
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
131
125
|
(0, _swagger.ApiBearerAuth)(),
|
|
132
126
|
(0, _swagger.ApiOperation)({
|
|
133
127
|
summary: "Get user's available companies",
|
|
@@ -142,14 +136,27 @@ _ts_decorate([
|
|
|
142
136
|
], CompanySelectionController.prototype, "getUserCompanies", null);
|
|
143
137
|
_ts_decorate([
|
|
144
138
|
(0, _common.UseGuards)(_guards.JwtAuthGuard),
|
|
145
|
-
(0, _common.
|
|
139
|
+
(0, _common.Post)('get-company-branches'),
|
|
140
|
+
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
146
141
|
(0, _swagger.ApiBearerAuth)(),
|
|
147
142
|
(0, _swagger.ApiOperation)({
|
|
148
143
|
summary: 'Get branches for a company',
|
|
149
144
|
description: 'Get list of branches for a specific company that the user has access to'
|
|
150
145
|
}),
|
|
146
|
+
(0, _swagger.ApiBody)({
|
|
147
|
+
schema: {
|
|
148
|
+
properties: {
|
|
149
|
+
companyId: {
|
|
150
|
+
type: 'string'
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
required: [
|
|
154
|
+
'companyId'
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
}),
|
|
151
158
|
_ts_param(0, (0, _decorators.CurrentUser)('id')),
|
|
152
|
-
_ts_param(1, (0, _common.
|
|
159
|
+
_ts_param(1, (0, _common.Body)('companyId')),
|
|
153
160
|
_ts_metadata("design:type", Function),
|
|
154
161
|
_ts_metadata("design:paramtypes", [
|
|
155
162
|
String,
|