@flusys/ng-auth 4.1.1 → 5.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 +70 -394
- package/fesm2022/flusys-ng-auth.mjs +3082 -2021
- package/fesm2022/flusys-ng-auth.mjs.map +1 -1
- package/package.json +4 -4
- package/types/flusys-ng-auth.d.ts +55 -161
package/README.md
CHANGED
|
@@ -1,67 +1,9 @@
|
|
|
1
1
|
# @flusys/ng-auth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
JWT authentication library for FLUSYS Angular apps — login, session restore, token refresh, multi-company selection, and provider adapter registration.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@flusys/ng-auth)
|
|
6
|
-
[](https://www.typescriptlang.org)
|
|
8
|
-
[](LICENSE)
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Table of Contents
|
|
13
|
-
|
|
14
|
-
- [Overview](#overview)
|
|
15
|
-
- [Features](#features)
|
|
16
|
-
- [Compatibility](#compatibility)
|
|
17
|
-
- [Installation](#installation)
|
|
18
|
-
- [Quick Start](#quick-start)
|
|
19
|
-
- [Module Registration](#module-registration)
|
|
20
|
-
- [Session Restoration Flow](#session-restoration-flow)
|
|
21
|
-
- [Auth State Service](#auth-state-service)
|
|
22
|
-
- [Auth API Service](#auth-api-service)
|
|
23
|
-
- [HTTP Interceptors](#http-interceptors)
|
|
24
|
-
- [Guards](#guards)
|
|
25
|
-
- [Pages](#pages)
|
|
26
|
-
- [Provider Adapters](#provider-adapters)
|
|
27
|
-
- [API Endpoints](#api-endpoints)
|
|
28
|
-
- [Configuration Reference](#configuration-reference)
|
|
29
|
-
- [Troubleshooting](#troubleshooting)
|
|
30
|
-
- [License](#license)
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## Overview
|
|
35
|
-
|
|
36
|
-
`@flusys/ng-auth` provides end-to-end authentication for FLUSYS Angular applications. It handles the complete lifecycle: login, registration, token refresh, session restoration on page reload, email verification, profile management, password changes, and multi-company selection.
|
|
37
|
-
|
|
38
|
-
Tokens are stored in **HTTP-only cookies** (managed by the backend) — never in localStorage. The access token is held in memory only and automatically refreshed via a silent refresh interceptor.
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## Features
|
|
43
|
-
|
|
44
|
-
- ✅ JWT authentication with HTTP-only refresh token cookies
|
|
45
|
-
- ✅ Silent token refresh on 401 responses
|
|
46
|
-
- ✅ Session restoration on page reload (`AuthInitService`)
|
|
47
|
-
- ✅ Multi-company selection flow
|
|
48
|
-
- ✅ Email verification with OTP
|
|
49
|
-
- ✅ Profile management (name, password, avatar)
|
|
50
|
-
- ✅ `AuthStateService` — signal-based reactive auth state
|
|
51
|
-
- ✅ `provideAuthProviders()` — registers `USER_PROVIDER`, `COMPANY_PROVIDER`
|
|
52
|
-
- ✅ `provideAuthLayoutIntegration()` — bridges auth to layout
|
|
53
|
-
- ✅ Guard: `appInitGuard` for session restoration before navigation
|
|
54
|
-
- ✅ Guard: `AuthenticatedGuard`, `GuestGuard`, `CompanySelectedGuard`
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## Compatibility
|
|
59
|
-
|
|
60
|
-
| Package | Version |
|
|
61
|
-
|---------|---------|
|
|
62
|
-
| Angular | 21+ |
|
|
63
|
-
| @flusys/ng-core | 4.x |
|
|
64
|
-
| @flusys/ng-shared | 4.x |
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
65
7
|
|
|
66
8
|
---
|
|
67
9
|
|
|
@@ -71,406 +13,140 @@ Tokens are stored in **HTTP-only cookies** (managed by the backend) — never in
|
|
|
71
13
|
npm install @flusys/ng-auth @flusys/ng-core @flusys/ng-shared
|
|
72
14
|
```
|
|
73
15
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
## Quick Start
|
|
77
|
-
|
|
78
|
-
### 1. Register Auth Providers
|
|
16
|
+
## 1. Register Providers
|
|
79
17
|
|
|
80
18
|
```typescript
|
|
81
19
|
// app.config.ts
|
|
82
|
-
import { ApplicationConfig } from '@angular/core';
|
|
83
20
|
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
84
|
-
import {
|
|
85
|
-
import {
|
|
86
|
-
provideAuthProviders,
|
|
87
|
-
provideAuthLayoutIntegration,
|
|
88
|
-
authInterceptor,
|
|
89
|
-
tokenRefreshInterceptor,
|
|
90
|
-
} from '@flusys/ng-auth';
|
|
91
|
-
import { environment } from './environments/environment';
|
|
21
|
+
import { provideAuthProviders, provideAuthLayoutIntegration, authInterceptor, tokenRefreshInterceptor } from '@flusys/ng-auth';
|
|
92
22
|
|
|
93
23
|
export const appConfig: ApplicationConfig = {
|
|
94
24
|
providers: [
|
|
95
|
-
{ provide: APP_CONFIG, useValue: environment },
|
|
96
25
|
provideHttpClient(
|
|
97
26
|
withInterceptors([
|
|
98
|
-
authInterceptor,
|
|
99
|
-
tokenRefreshInterceptor,
|
|
27
|
+
authInterceptor, // attaches Bearer token; sends withCredentials for cookie endpoints
|
|
28
|
+
tokenRefreshInterceptor, // proactive + reactive refresh; queues concurrent 401s
|
|
100
29
|
])
|
|
101
30
|
),
|
|
102
|
-
...provideAuthProviders(),
|
|
103
|
-
...provideAuthLayoutIntegration(),
|
|
31
|
+
...provideAuthProviders(), // USER_PROVIDER, COMPANY_API_PROVIDER, USER_PERMISSION_PROVIDER, AUTH_STATE_PROVIDER
|
|
32
|
+
...provideAuthLayoutIntegration(), // LAYOUT_AUTH_STATE, LAYOUT_AUTH_API
|
|
104
33
|
],
|
|
105
34
|
};
|
|
106
35
|
```
|
|
107
36
|
|
|
108
|
-
|
|
37
|
+
Interceptor order matters: `authInterceptor` must come before `tokenRefreshInterceptor`.
|
|
38
|
+
|
|
39
|
+
## 2. Add Routes
|
|
109
40
|
|
|
110
41
|
```typescript
|
|
111
42
|
// app.routes.ts
|
|
112
|
-
import {
|
|
113
|
-
import { appInitGuard } from '@flusys/ng-auth';
|
|
114
|
-
import { AppLayoutComponent } from '@flusys/ng-layout';
|
|
43
|
+
import { AUTH_ROUTES, ADMINISTRATION_ROUTES, PROFILE_ROUTES } from '@flusys/ng-auth';
|
|
115
44
|
|
|
116
45
|
export const routes: Routes = [
|
|
117
46
|
{
|
|
118
|
-
path: '',
|
|
119
|
-
|
|
120
|
-
canActivate: [appInitGuard], // Restores session on page refresh
|
|
121
|
-
children: [
|
|
122
|
-
{ path: 'dashboard', loadComponent: () => import('./pages/dashboard.component') },
|
|
123
|
-
],
|
|
47
|
+
path: 'auth',
|
|
48
|
+
loadChildren: () => AUTH_ROUTES, // login, register, forgot-password, reset-password, verify-email
|
|
124
49
|
},
|
|
125
50
|
{
|
|
126
|
-
path: '
|
|
127
|
-
loadChildren: () =>
|
|
51
|
+
path: 'administration',
|
|
52
|
+
loadChildren: () => ADMINISTRATION_ROUTES, // users, company, branch (protected by authGuard)
|
|
128
53
|
},
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
### 3. Enable Auth in App Config
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
// environments/environment.ts
|
|
136
|
-
export const environment = {
|
|
137
|
-
apiBaseUrl: 'http://localhost:2002',
|
|
138
|
-
services: {
|
|
139
|
-
auth: {
|
|
140
|
-
enabled: true,
|
|
141
|
-
features: {
|
|
142
|
-
signUp: true,
|
|
143
|
-
emailVerification: true,
|
|
144
|
-
companySelection: true,
|
|
145
|
-
},
|
|
146
|
-
},
|
|
54
|
+
{
|
|
55
|
+
path: 'profile',
|
|
56
|
+
loadChildren: () => PROFILE_ROUTES, // profile page (protected by authGuard)
|
|
147
57
|
},
|
|
148
|
-
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## Module Registration
|
|
154
|
-
|
|
155
|
-
`ng-auth` uses function-based providers (not Angular modules):
|
|
156
|
-
|
|
157
|
-
### `provideAuthProviders()`
|
|
158
|
-
|
|
159
|
-
Registers auth adapters against shared provider tokens:
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
...provideAuthProviders()
|
|
163
|
-
|
|
164
|
-
// Provides:
|
|
165
|
-
// USER_PROVIDER → AuthStateService (IUserProvider)
|
|
166
|
-
// COMPANY_PROVIDER → AuthStateService (ICompanyProvider)
|
|
58
|
+
];
|
|
167
59
|
```
|
|
168
60
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
### `provideAuthLayoutIntegration()`
|
|
172
|
-
|
|
173
|
-
Bridges auth state and API to the layout:
|
|
61
|
+
## 3. Protect Routes with Guards
|
|
174
62
|
|
|
175
63
|
```typescript
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// Provides:
|
|
179
|
-
// LAYOUT_AUTH_STATE → AuthLayoutStateAdapter (profile picture, company logo)
|
|
180
|
-
// LAYOUT_AUTH_API → AuthLayoutApiAdapter (logout, select-company actions)
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## Session Restoration Flow
|
|
64
|
+
import { authGuard, guestGuard, companyFeatureGuard } from '@flusys/ng-auth';
|
|
186
65
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
├─ POST /auth/refresh (HTTP-only cookie) → access token
|
|
200
|
-
├─ GET /auth/me → user data
|
|
201
|
-
└─ Session restored in memory
|
|
202
|
-
│
|
|
203
|
-
├─ Auth enabled? → Check company selection
|
|
204
|
-
├─ IAM enabled? → Load permissions
|
|
205
|
-
└─ Allow navigation
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### Company Selection Flow
|
|
209
|
-
|
|
210
|
-
```
|
|
211
|
-
User logs in
|
|
212
|
-
│
|
|
213
|
-
├─ requiresSelection: false ──► Navigate to app
|
|
214
|
-
│
|
|
215
|
-
└─ requiresSelection: true
|
|
216
|
-
│
|
|
217
|
-
├─ sessionId + companies[] returned
|
|
218
|
-
└─ Redirect to /auth/select-company
|
|
219
|
-
│
|
|
220
|
-
└─ User picks company/branch
|
|
221
|
-
│
|
|
222
|
-
└─ POST /auth/select { sessionId, companyId, branchId }
|
|
223
|
-
│
|
|
224
|
-
└─ Tokens + company data → Navigate to app
|
|
66
|
+
const routes: Routes = [
|
|
67
|
+
{
|
|
68
|
+
path: 'dashboard',
|
|
69
|
+
canActivate: [authGuard], // redirects to /auth/login if not authenticated
|
|
70
|
+
loadComponent: () => import('./dashboard.component'),
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
path: 'auth/login',
|
|
74
|
+
canActivate: [guestGuard], // redirects to '/' if already authenticated; restores session first
|
|
75
|
+
loadComponent: () => import('./login.component'),
|
|
76
|
+
},
|
|
77
|
+
];
|
|
225
78
|
```
|
|
226
79
|
|
|
227
|
-
|
|
80
|
+
| Guard | Exported name | Behavior |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| Require auth | `authGuard` | Redirects to `/auth/login`; checks company if `enableCompanyFeature` is on |
|
|
83
|
+
| Require guest | `guestGuard` | Redirects to `/` (or `returnUrl`) if authenticated; calls `AuthInitService.initialize()` |
|
|
84
|
+
| Require company feature | `companyFeatureGuard` | Redirects to `/` if company feature is disabled in config |
|
|
228
85
|
|
|
229
|
-
## Auth State
|
|
86
|
+
## 4. Read Auth State
|
|
230
87
|
|
|
231
|
-
`AuthStateService`
|
|
88
|
+
`AuthStateService` holds all auth state as read-only signals. The access token is memory-only (never persisted).
|
|
232
89
|
|
|
233
90
|
```typescript
|
|
234
91
|
import { AuthStateService } from '@flusys/ng-auth';
|
|
235
92
|
|
|
236
93
|
@Component({ ... })
|
|
237
94
|
export class MyComponent {
|
|
238
|
-
private authState = inject(AuthStateService);
|
|
239
|
-
|
|
240
|
-
// Signals (read-only)
|
|
241
|
-
user = this.authState.user; // Signal<ICurrentUser | null>
|
|
242
|
-
company = this.authState.company; // Signal<ICompany | null>
|
|
243
|
-
branch = this.authState.branch; // Signal<IBranch | null>
|
|
244
|
-
isAuthenticated = this.authState.isAuthenticated; // Signal<boolean>
|
|
245
|
-
accessToken = this.authState.accessToken; // Signal<string | null>
|
|
246
|
-
|
|
247
|
-
// Computed
|
|
248
|
-
userName = computed(() => this.authState.user()?.name ?? 'Guest');
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
**AuthStateService API:**
|
|
253
|
-
|
|
254
|
-
| Member | Type | Description |
|
|
255
|
-
|--------|------|-------------|
|
|
256
|
-
| `user` | `Signal<ICurrentUser \| null>` | Current authenticated user |
|
|
257
|
-
| `company` | `Signal<ICompany \| null>` | Selected company |
|
|
258
|
-
| `branch` | `Signal<IBranch \| null>` | Selected branch |
|
|
259
|
-
| `isAuthenticated` | `Signal<boolean>` | True if user is logged in |
|
|
260
|
-
| `accessToken` | `Signal<string \| null>` | In-memory JWT access token |
|
|
261
|
-
| `setUser(user)` | `void` | Update user state |
|
|
262
|
-
| `setTokens(tokens)` | `void` | Update access token |
|
|
263
|
-
| `setCompany(company, branch)` | `void` | Update company/branch |
|
|
264
|
-
| `clearAll()` | `void` | Clear all auth state (logout) |
|
|
95
|
+
private readonly authState = inject(AuthStateService);
|
|
265
96
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
```typescript
|
|
273
|
-
import { AuthApiService } from '@flusys/ng-auth';
|
|
274
|
-
|
|
275
|
-
@Component({ ... })
|
|
276
|
-
export class LoginPageComponent {
|
|
277
|
-
private authApi = inject(AuthApiService);
|
|
278
|
-
|
|
279
|
-
login(email: string, password: string): void {
|
|
280
|
-
this.authApi.login({ email, password }).subscribe(response => {
|
|
281
|
-
if (response.requiresSelection) {
|
|
282
|
-
// Redirect to company selection
|
|
283
|
-
}
|
|
284
|
-
// Navigate to app
|
|
285
|
-
});
|
|
286
|
-
}
|
|
97
|
+
readonly user = this.authState.user; // Signal<IUserInfo | null>
|
|
98
|
+
readonly company = this.authState.company; // Signal<ICompanyInfo | null>
|
|
99
|
+
readonly branch = this.authState.branch; // Signal<IBranchInfo | null>
|
|
100
|
+
readonly isAuth = this.authState.isAuthenticated; // Signal<boolean>
|
|
101
|
+
readonly tokenExpired = this.authState.isTokenExpired; // Signal<boolean>
|
|
287
102
|
}
|
|
288
103
|
```
|
|
289
104
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
| Method | Endpoint | Description |
|
|
293
|
-
|--------|----------|-------------|
|
|
294
|
-
| `login(dto)` | `POST /auth/login` | Authenticate user |
|
|
295
|
-
| `register(dto)` | `POST /auth/register` | Self-register |
|
|
296
|
-
| `logout()` | `POST /auth/logout` | Invalidate tokens |
|
|
297
|
-
| `refresh()` | `POST /auth/refresh` | Refresh access token |
|
|
298
|
-
| `me()` | `GET /auth/me` | Get current user info |
|
|
299
|
-
| `selectCompany(dto)` | `POST /auth/select` | Select company after login |
|
|
300
|
-
| `verifyEmail(dto)` | `POST /auth/verify-email` | Verify OTP |
|
|
301
|
-
| `resendVerification()` | `POST /auth/resend-verification` | Resend OTP email |
|
|
302
|
-
| `changePassword(dto)` | `POST /auth/change-password` | Update password |
|
|
303
|
-
| `updateProfile(dto)` | `POST /auth/update-profile` | Update name/avatar |
|
|
304
|
-
|
|
305
|
-
---
|
|
306
|
-
|
|
307
|
-
## HTTP Interceptors
|
|
308
|
-
|
|
309
|
-
### authInterceptor
|
|
310
|
-
|
|
311
|
-
Attaches the in-memory access token as `Authorization: Bearer <token>` header to every outgoing request (except public endpoints).
|
|
105
|
+
Key state methods:
|
|
312
106
|
|
|
313
107
|
```typescript
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
)
|
|
108
|
+
authState.setLoginState(data); // sets user + token + company + branch
|
|
109
|
+
authState.setSelectionState(data); // multi-company selection flow
|
|
110
|
+
authState.resetState(); // logout — clears all state + localStorage
|
|
111
|
+
authState.navigateToLogin(returnUrl?); // safe redirect (rejects external URLs)
|
|
317
112
|
```
|
|
318
113
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
On 401 responses, automatically:
|
|
322
|
-
1. Calls `POST /auth/refresh`
|
|
323
|
-
2. Updates `AuthStateService` with new token
|
|
324
|
-
3. Retries the original failed request
|
|
114
|
+
## 6. Session Restore
|
|
325
115
|
|
|
326
|
-
|
|
116
|
+
`AuthInitService.initialize()` runs `POST /auth/refresh` (HTTP-only cookie) then `POST /auth/me` to restore session in memory. It is called automatically by `guestGuard`. Call it manually if needed:
|
|
327
117
|
|
|
328
118
|
```typescript
|
|
329
|
-
|
|
330
|
-
withInterceptors([tokenRefreshInterceptor])
|
|
331
|
-
)
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
**Interceptor Order Matters:**
|
|
119
|
+
import { AuthInitService } from '@flusys/ng-auth';
|
|
335
120
|
|
|
336
|
-
|
|
337
|
-
withInterceptors([
|
|
338
|
-
authInterceptor, // Must be FIRST (attaches token)
|
|
339
|
-
tokenRefreshInterceptor, // Must be SECOND (handles 401)
|
|
340
|
-
])
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
---
|
|
344
|
-
|
|
345
|
-
## Guards
|
|
346
|
-
|
|
347
|
-
| Guard | Usage | Behavior |
|
|
348
|
-
|-------|-------|---------|
|
|
349
|
-
| `appInitGuard` | `canActivate` | Restores session from cookie on page refresh |
|
|
350
|
-
| `AuthenticatedGuard` | `canActivate` | Redirects to `/auth/login` if not authenticated |
|
|
351
|
-
| `GuestGuard` | `canActivate` | Redirects to `/` if already authenticated |
|
|
352
|
-
| `CompanySelectedGuard` | `canActivate` | Redirects to `/auth/select-company` if company not chosen |
|
|
353
|
-
|
|
354
|
-
```typescript
|
|
355
|
-
// Route with all guards
|
|
356
|
-
{
|
|
357
|
-
path: '',
|
|
358
|
-
canActivate: [appInitGuard],
|
|
359
|
-
children: [
|
|
360
|
-
{
|
|
361
|
-
path: 'dashboard',
|
|
362
|
-
canActivate: [AuthenticatedGuard, CompanySelectedGuard],
|
|
363
|
-
loadComponent: () => import('./dashboard.component'),
|
|
364
|
-
},
|
|
365
|
-
],
|
|
366
|
-
}
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
---
|
|
370
|
-
|
|
371
|
-
## Pages
|
|
372
|
-
|
|
373
|
-
`ng-auth` exports pre-built page components routable via `AUTH_ROUTES`:
|
|
374
|
-
|
|
375
|
-
```typescript
|
|
376
|
-
import { AUTH_ROUTES } from '@flusys/ng-auth';
|
|
121
|
+
const authInit = inject(AuthInitService);
|
|
377
122
|
|
|
378
|
-
|
|
379
|
-
|
|
123
|
+
authInit.initialize().subscribe(isAuthenticated => {
|
|
124
|
+
// safe to read authState signals now
|
|
125
|
+
});
|
|
380
126
|
```
|
|
381
127
|
|
|
382
|
-
|
|
383
|
-
|-------|-----------|-------------|
|
|
384
|
-
| `/auth/login` | `LoginPageComponent` | Email + password login form |
|
|
385
|
-
| `/auth/register` | `RegisterPageComponent` | Self-registration form |
|
|
386
|
-
| `/auth/verify-email` | `VerifyEmailPageComponent` | OTP verification |
|
|
387
|
-
| `/auth/select-company` | `SelectCompanyPageComponent` | Company/branch picker |
|
|
388
|
-
| `/auth/profile` | `ProfilePageComponent` | User profile editor |
|
|
389
|
-
|
|
390
|
-
All pages support full i18n via `TranslatePipe`.
|
|
391
|
-
|
|
392
|
-
---
|
|
393
|
-
|
|
394
|
-
## Provider Adapters
|
|
128
|
+
The `initialized` signal is `true` after the first call completes (success or failure).
|
|
395
129
|
|
|
396
|
-
|
|
130
|
+
## 7. Extend Registration / Profile (Optional)
|
|
397
131
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
### User Enricher
|
|
401
|
-
|
|
402
|
-
You can inject additional user data at login time:
|
|
132
|
+
Inject custom fields and sections via extension tokens:
|
|
403
133
|
|
|
404
134
|
```typescript
|
|
405
|
-
|
|
406
|
-
import { USER_ENRICHER } from '@flusys/ng-auth';
|
|
135
|
+
import { AUTH_REGISTRATION_EXTENSION, AUTH_PROFILE_EXTENSION, AUTH_USER_LIST_EXTENSION, AUTH_VALIDATION_CONFIG } from '@flusys/ng-auth';
|
|
407
136
|
|
|
408
137
|
providers: [
|
|
138
|
+
{ provide: AUTH_REGISTRATION_EXTENSION, useClass: MyRegistrationExtension }, // extra fields on register form
|
|
139
|
+
{ provide: AUTH_PROFILE_EXTENSION, useClass: MyProfileExtension }, // extra sections on profile page
|
|
140
|
+
{ provide: AUTH_USER_LIST_EXTENSION, useClass: MyUserListExtension }, // extra columns/actions on user list
|
|
409
141
|
{
|
|
410
|
-
provide:
|
|
411
|
-
|
|
142
|
+
provide: AUTH_VALIDATION_CONFIG,
|
|
143
|
+
useValue: {
|
|
144
|
+
password: { minLength: 10, requireUppercase: true, requireSpecialChars: true },
|
|
145
|
+
},
|
|
412
146
|
},
|
|
413
147
|
]
|
|
414
148
|
```
|
|
415
149
|
|
|
416
|
-
---
|
|
417
|
-
|
|
418
|
-
## API Endpoints
|
|
419
|
-
|
|
420
|
-
| Method | Endpoint | Auth | Description |
|
|
421
|
-
|--------|----------|------|-------------|
|
|
422
|
-
| POST | `/auth/login` | Public | Login with email/password |
|
|
423
|
-
| POST | `/auth/register` | Public | Self-registration |
|
|
424
|
-
| POST | `/auth/logout` | Bearer | Logout and clear cookie |
|
|
425
|
-
| POST | `/auth/refresh` | Cookie | Refresh access token |
|
|
426
|
-
| GET | `/auth/me` | Bearer | Get current user |
|
|
427
|
-
| POST | `/auth/select` | Session | Select company after login |
|
|
428
|
-
| POST | `/auth/verify-email` | Bearer | Verify email OTP |
|
|
429
|
-
| POST | `/auth/resend-verification` | Bearer | Resend OTP |
|
|
430
|
-
| POST | `/auth/change-password` | Bearer | Change password |
|
|
431
|
-
| POST | `/auth/update-profile` | Bearer | Update profile |
|
|
432
|
-
|
|
433
|
-
---
|
|
434
|
-
|
|
435
|
-
## Configuration Reference
|
|
436
|
-
|
|
437
|
-
| Config Key | Type | Default | Description |
|
|
438
|
-
|------------|------|---------|-------------|
|
|
439
|
-
| `services.auth.enabled` | `boolean` | `false` | Enable auth module |
|
|
440
|
-
| `services.auth.features.signUp` | `boolean` | `false` | Allow self-registration |
|
|
441
|
-
| `services.auth.features.emailVerification` | `boolean` | `false` | Require email OTP |
|
|
442
|
-
| `services.auth.features.companySelection` | `boolean` | `false` | Enable multi-company |
|
|
443
|
-
|
|
444
|
-
---
|
|
445
|
-
|
|
446
|
-
## Troubleshooting
|
|
447
|
-
|
|
448
|
-
**Token refresh loop (endless 401 cycle)**
|
|
449
|
-
|
|
450
|
-
This happens when the refresh endpoint itself returns 401. Ensure the refresh token cookie hasn't expired. Also verify that `tokenRefreshInterceptor` skips the `/auth/refresh` endpoint:
|
|
451
|
-
|
|
452
|
-
```typescript
|
|
453
|
-
// The interceptor automatically skips /auth/refresh to prevent loops
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
**`appInitGuard` redirects to login on every refresh**
|
|
457
|
-
|
|
458
|
-
Ensure your backend sets the refresh token cookie with `httpOnly: true`, `sameSite: 'lax'`, and the correct `domain`/`path`. The browser must send the cookie automatically with `POST /auth/refresh`.
|
|
459
|
-
|
|
460
|
-
**Company selection page shown even after selecting**
|
|
461
|
-
|
|
462
|
-
Verify that `POST /auth/select` returns both tokens AND the company/branch data. `AuthStateService.setCompany()` must be called with the response.
|
|
463
|
-
|
|
464
|
-
**User profile picture doesn't load**
|
|
465
|
-
|
|
466
|
-
Profile pictures are fetched via `FileUrlService`, not by constructing URLs. Ensure `ng-storage` providers are registered and `services.storage.enabled: true`.
|
|
467
|
-
|
|
468
|
-
**Login form validation errors not translated**
|
|
469
|
-
|
|
470
|
-
Provide `TRANSLATE_ADAPTER` via `provideLocalization()`. The fallback text (non-translated) is always shown if the adapter is absent.
|
|
471
|
-
|
|
472
|
-
---
|
|
473
|
-
|
|
474
150
|
## License
|
|
475
151
|
|
|
476
152
|
MIT © FLUSYS
|