@medha-analytics/medhasso-auth 1.0.0 → 1.0.1
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
CHANGED
|
@@ -1,297 +1,297 @@
|
|
|
1
|
-
# MedHasso Authentication Library
|
|
2
|
-
|
|
3
|
-
Angular authentication library for seamless integration with MedHasso SSO services. This library provides JWT token management, route guards, HTTP interceptors, and user management utilities.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- 🔐 **JWT Token Management** - Automatic token refresh and storage
|
|
8
|
-
- 🛡️ **Route Guards** - Protect routes with authentication and role-based access
|
|
9
|
-
- 🔄 **HTTP Interceptor** - Automatic token attachment to HTTP requests
|
|
10
|
-
- 👤 **User Management** - Extract and manage user information from JWT tokens
|
|
11
|
-
- ⚙️ **Configurable** - Extensive configuration options for different environments
|
|
12
|
-
- 📱 **Angular 14+ Support** - Compatible with Angular 14 through latest versions
|
|
13
|
-
|
|
14
|
-
## Installation
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm install @medha-analytics/medhasso-auth
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Quick Start
|
|
21
|
-
|
|
22
|
-
### 1. Import and Configure
|
|
23
|
-
|
|
24
|
-
In your `app.config.ts` (Angular 17+ standalone) or `app.module.ts`:
|
|
25
|
-
|
|
26
|
-
#### Standalone Bootstrap (Angular 17+)
|
|
27
|
-
```typescript
|
|
28
|
-
import { bootstrapApplication } from '@angular/platform-browser';
|
|
29
|
-
import { provideRouter } from '@angular/router';
|
|
30
|
-
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
|
31
|
-
import { MedHassoAuthModule } from '@medha-analytics/medhasso-auth';
|
|
32
|
-
import { AppComponent } from './app/app.component';
|
|
33
|
-
import { routes } from './app/app.routes';
|
|
34
|
-
import { environment } from './environments/environment';
|
|
35
|
-
|
|
36
|
-
bootstrapApplication(AppComponent, {
|
|
37
|
-
providers: [
|
|
38
|
-
provideRouter(routes),
|
|
39
|
-
provideHttpClient(withInterceptorsFromDi()),
|
|
40
|
-
...MedHassoAuthModule.forStandalone({
|
|
41
|
-
ssoUrl: environment.ssoUrl,
|
|
42
|
-
refreshUrl: environment.refreshUrl,
|
|
43
|
-
applicationName: 'Your App Name'
|
|
44
|
-
})
|
|
45
|
-
]
|
|
46
|
-
});
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
#### Module-based (Angular 14-16)
|
|
50
|
-
```typescript
|
|
51
|
-
import { NgModule } from '@angular/core';
|
|
52
|
-
import { BrowserModule } from '@angular/platform-browser';
|
|
53
|
-
import { HttpClientModule } from '@angular/common/http';
|
|
54
|
-
import { MedHassoAuthModule } from '@medha-analytics/medhasso-auth';
|
|
55
|
-
import { AppComponent } from './app.component';
|
|
56
|
-
import { environment } from '../environments/environment';
|
|
57
|
-
|
|
58
|
-
@NgModule({
|
|
59
|
-
declarations: [AppComponent],
|
|
60
|
-
imports: [
|
|
61
|
-
BrowserModule,
|
|
62
|
-
HttpClientModule,
|
|
63
|
-
MedHassoAuthModule.forRoot({
|
|
64
|
-
ssoUrl: environment.ssoUrl,
|
|
65
|
-
refreshUrl: environment.refreshUrl,
|
|
66
|
-
applicationName: 'Your App Name'
|
|
67
|
-
})
|
|
68
|
-
],
|
|
69
|
-
bootstrap: [AppComponent]
|
|
70
|
-
})
|
|
71
|
-
export class AppModule { }
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### 2. Protect Routes
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
import { Routes } from '@angular/router';
|
|
78
|
-
import { MedHassoAuthGuard, MedHassoRoleGuard, MedHassoAdminGuard } from '@medha-analytics/medhasso-auth';
|
|
79
|
-
|
|
80
|
-
export const routes: Routes = [
|
|
81
|
-
{
|
|
82
|
-
path: 'dashboard',
|
|
83
|
-
component: DashboardComponent,
|
|
84
|
-
canActivate: [MedHassoAuthGuard]
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
path: 'admin',
|
|
88
|
-
component: AdminComponent,
|
|
89
|
-
canActivate: [MedHassoAdminGuard]
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
path: 'manager',
|
|
93
|
-
component: ManagerComponent,
|
|
94
|
-
canActivate: [MedHassoRoleGuard],
|
|
95
|
-
data: { roles: ['manager', 'admin'] }
|
|
96
|
-
}
|
|
97
|
-
];
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### 3. Use in Components
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
import { Component } from '@angular/core';
|
|
104
|
-
import { MedHassoAuthService } from '@medha-analytics/medhasso-auth';
|
|
105
|
-
|
|
106
|
-
@Component({
|
|
107
|
-
selector: 'app-user-profile',
|
|
108
|
-
template: `
|
|
109
|
-
<div *ngIf="authService.isAuthenticated()">
|
|
110
|
-
<h2>Welcome, {{ authService.getUserDisplayName() }}!</h2>
|
|
111
|
-
<p>Email: {{ authService.getUserEmail() }}</p>
|
|
112
|
-
<div *ngIf="authService.isAdmin()">
|
|
113
|
-
<button>Admin Panel</button>
|
|
114
|
-
</div>
|
|
115
|
-
<button (click)="logout()">Logout</button>
|
|
116
|
-
</div>
|
|
117
|
-
`
|
|
118
|
-
})
|
|
119
|
-
export class UserProfileComponent {
|
|
120
|
-
constructor(public authService: MedHassoAuthService) {}
|
|
121
|
-
|
|
122
|
-
logout() {
|
|
123
|
-
this.authService.logout();
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Configuration Options
|
|
129
|
-
|
|
130
|
-
### Environment Setup
|
|
131
|
-
First, configure your environment files:
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
// src/environments/environment.ts
|
|
135
|
-
export const environment = {
|
|
136
|
-
production: false,
|
|
137
|
-
ssoUrl: 'https://your-dev-sso.domain.com:3000',
|
|
138
|
-
refreshUrl: 'https://your-dev-refresh.domain.com:4000',
|
|
139
|
-
// ... other config
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
// src/environments/environment.production.ts
|
|
143
|
-
export const environment = {
|
|
144
|
-
production: true,
|
|
145
|
-
ssoUrl: 'https://your-prod-sso.domain.com:3000',
|
|
146
|
-
refreshUrl: 'https://your-prod-refresh.domain.com:4000',
|
|
147
|
-
// ... other config
|
|
148
|
-
};
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Basic Configuration
|
|
152
|
-
```typescript
|
|
153
|
-
{
|
|
154
|
-
ssoUrl: environment.ssoUrl,
|
|
155
|
-
refreshUrl: environment.refreshUrl,
|
|
156
|
-
applicationName: 'Your Application Name'
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Advanced Configuration
|
|
161
|
-
```typescript
|
|
162
|
-
{
|
|
163
|
-
ssoUrl: environment.ssoUrl,
|
|
164
|
-
refreshUrl: environment.refreshUrl,
|
|
165
|
-
applicationName: 'Your Application Name',
|
|
166
|
-
|
|
167
|
-
// Token configuration
|
|
168
|
-
tokenConfig: {
|
|
169
|
-
storageType: 'localStorage', // or 'sessionStorage'
|
|
170
|
-
idTokenKey: 'idToken',
|
|
171
|
-
refreshTokenKey: 'refreshToken',
|
|
172
|
-
refreshBeforeExpiryMinutes: 5,
|
|
173
|
-
autoRefresh: true
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
// HTTP Interceptor configuration
|
|
177
|
-
interceptorConfig: {
|
|
178
|
-
enabled: true,
|
|
179
|
-
authHeaderPrefix: 'Bearer',
|
|
180
|
-
excludeUrls: ['*/public/*', '*/assets/*'],
|
|
181
|
-
includeUrls: ['*/api/*'] // Optional: if specified, only these URLs get tokens
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
// Security configuration
|
|
185
|
-
securityConfig: {
|
|
186
|
-
httpsOnly: true,
|
|
187
|
-
secureCookies: true,
|
|
188
|
-
additionalCspSources: ['https://your-cdn.com']
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
## Guards
|
|
194
|
-
|
|
195
|
-
### MedHassoAuthGuard
|
|
196
|
-
Basic authentication guard that ensures user is logged in.
|
|
197
|
-
|
|
198
|
-
### MedHassoRoleGuard
|
|
199
|
-
Role-based access guard. Use with route data:
|
|
200
|
-
```typescript
|
|
201
|
-
{
|
|
202
|
-
path: 'admin',
|
|
203
|
-
component: AdminComponent,
|
|
204
|
-
canActivate: [MedHassoRoleGuard],
|
|
205
|
-
data: {
|
|
206
|
-
role: 'admin', // Single role
|
|
207
|
-
roles: ['admin', 'manager'] // Multiple roles (OR condition)
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### MedHassoAdminGuard
|
|
213
|
-
Admin-only access guard.
|
|
214
|
-
|
|
215
|
-
## Services
|
|
216
|
-
|
|
217
|
-
### MedHassoAuthService
|
|
218
|
-
Main authentication service with methods:
|
|
219
|
-
- `isAuthenticated(): boolean`
|
|
220
|
-
- `getCurrentUser(): MedHassoUser | null`
|
|
221
|
-
- `hasRole(role: string): boolean`
|
|
222
|
-
- `isAdmin(): boolean`
|
|
223
|
-
- `login(returnUrl?: string): void`
|
|
224
|
-
- `logout(): void`
|
|
225
|
-
- `getUserEmail(): string | null`
|
|
226
|
-
- `getUserDisplayName(): string | null`
|
|
227
|
-
|
|
228
|
-
### TokenManagementService
|
|
229
|
-
Low-level token management (usually not needed directly):
|
|
230
|
-
- `getTokenInfo(): TokenInfo | null`
|
|
231
|
-
- `refreshToken(): Observable<any>`
|
|
232
|
-
- `setTokens(idToken: string, refreshToken?: string): void`
|
|
233
|
-
|
|
234
|
-
## Environment-Specific Setup
|
|
235
|
-
|
|
236
|
-
### Development
|
|
237
|
-
```typescript
|
|
238
|
-
// src/environments/environment.ts
|
|
239
|
-
export const environment = {
|
|
240
|
-
production: false,
|
|
241
|
-
ssoUrl: 'https://dev-sso.your-domain.com:3000',
|
|
242
|
-
refreshUrl: 'https://dev-refresh.your-domain.com:4000'
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
// Usage in module/config
|
|
246
|
-
MedHassoAuthModule.forRoot({
|
|
247
|
-
ssoUrl: environment.ssoUrl,
|
|
248
|
-
refreshUrl: environment.refreshUrl,
|
|
249
|
-
applicationName: 'Your App (Dev)'
|
|
250
|
-
})
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### Production
|
|
254
|
-
```typescript
|
|
255
|
-
// src/environments/environment.production.ts
|
|
256
|
-
export const environment = {
|
|
257
|
-
production: true,
|
|
258
|
-
ssoUrl: 'https://sso.your-domain.com:3000',
|
|
259
|
-
refreshUrl: 'https://refresh.your-domain.com:4000'
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
// Usage in module/config
|
|
263
|
-
MedHassoAuthModule.forRoot({
|
|
264
|
-
ssoUrl: environment.ssoUrl,
|
|
265
|
-
refreshUrl: environment.refreshUrl,
|
|
266
|
-
applicationName: 'Your App'
|
|
267
|
-
})
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
## CSP Configuration
|
|
271
|
-
|
|
272
|
-
For server-side Content Security Policy, include these domains:
|
|
273
|
-
|
|
274
|
-
```javascript
|
|
275
|
-
// In your server configuration (e.g., Express.js)
|
|
276
|
-
const cspSources = [
|
|
277
|
-
process.env.SSO_URL || 'https://your-sso.domain.com:3000',
|
|
278
|
-
process.env.REFRESH_URL || 'https://your-refresh.domain.com:4000'
|
|
279
|
-
];
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
## Migration Guide
|
|
283
|
-
|
|
284
|
-
### From Custom Implementation
|
|
285
|
-
1. Remove your existing auth guard, interceptor, and token service
|
|
286
|
-
2. Install this library
|
|
287
|
-
3. Update your imports and module configuration
|
|
288
|
-
4. Update route guards to use library guards
|
|
289
|
-
5. Update components to use `MedHassoAuthService`
|
|
290
|
-
|
|
291
|
-
## Contributing
|
|
292
|
-
|
|
293
|
-
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
294
|
-
|
|
295
|
-
## License
|
|
296
|
-
|
|
1
|
+
# MedHasso Authentication Library
|
|
2
|
+
|
|
3
|
+
Angular authentication library for seamless integration with MedHasso SSO services. This library provides JWT token management, route guards, HTTP interceptors, and user management utilities.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔐 **JWT Token Management** - Automatic token refresh and storage
|
|
8
|
+
- 🛡️ **Route Guards** - Protect routes with authentication and role-based access
|
|
9
|
+
- 🔄 **HTTP Interceptor** - Automatic token attachment to HTTP requests
|
|
10
|
+
- 👤 **User Management** - Extract and manage user information from JWT tokens
|
|
11
|
+
- ⚙️ **Configurable** - Extensive configuration options for different environments
|
|
12
|
+
- 📱 **Angular 14+ Support** - Compatible with Angular 14 through latest versions
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @medha-analytics/medhasso-auth
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### 1. Import and Configure
|
|
23
|
+
|
|
24
|
+
In your `app.config.ts` (Angular 17+ standalone) or `app.module.ts`:
|
|
25
|
+
|
|
26
|
+
#### Standalone Bootstrap (Angular 17+)
|
|
27
|
+
```typescript
|
|
28
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
29
|
+
import { provideRouter } from '@angular/router';
|
|
30
|
+
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
|
31
|
+
import { MedHassoAuthModule } from '@medha-analytics/medhasso-auth';
|
|
32
|
+
import { AppComponent } from './app/app.component';
|
|
33
|
+
import { routes } from './app/app.routes';
|
|
34
|
+
import { environment } from './environments/environment';
|
|
35
|
+
|
|
36
|
+
bootstrapApplication(AppComponent, {
|
|
37
|
+
providers: [
|
|
38
|
+
provideRouter(routes),
|
|
39
|
+
provideHttpClient(withInterceptorsFromDi()),
|
|
40
|
+
...MedHassoAuthModule.forStandalone({
|
|
41
|
+
ssoUrl: environment.ssoUrl,
|
|
42
|
+
refreshUrl: environment.refreshUrl,
|
|
43
|
+
applicationName: 'Your App Name'
|
|
44
|
+
})
|
|
45
|
+
]
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
#### Module-based (Angular 14-16)
|
|
50
|
+
```typescript
|
|
51
|
+
import { NgModule } from '@angular/core';
|
|
52
|
+
import { BrowserModule } from '@angular/platform-browser';
|
|
53
|
+
import { HttpClientModule } from '@angular/common/http';
|
|
54
|
+
import { MedHassoAuthModule } from '@medha-analytics/medhasso-auth';
|
|
55
|
+
import { AppComponent } from './app.component';
|
|
56
|
+
import { environment } from '../environments/environment';
|
|
57
|
+
|
|
58
|
+
@NgModule({
|
|
59
|
+
declarations: [AppComponent],
|
|
60
|
+
imports: [
|
|
61
|
+
BrowserModule,
|
|
62
|
+
HttpClientModule,
|
|
63
|
+
MedHassoAuthModule.forRoot({
|
|
64
|
+
ssoUrl: environment.ssoUrl,
|
|
65
|
+
refreshUrl: environment.refreshUrl,
|
|
66
|
+
applicationName: 'Your App Name'
|
|
67
|
+
})
|
|
68
|
+
],
|
|
69
|
+
bootstrap: [AppComponent]
|
|
70
|
+
})
|
|
71
|
+
export class AppModule { }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Protect Routes
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { Routes } from '@angular/router';
|
|
78
|
+
import { MedHassoAuthGuard, MedHassoRoleGuard, MedHassoAdminGuard } from '@medha-analytics/medhasso-auth';
|
|
79
|
+
|
|
80
|
+
export const routes: Routes = [
|
|
81
|
+
{
|
|
82
|
+
path: 'dashboard',
|
|
83
|
+
component: DashboardComponent,
|
|
84
|
+
canActivate: [MedHassoAuthGuard]
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
path: 'admin',
|
|
88
|
+
component: AdminComponent,
|
|
89
|
+
canActivate: [MedHassoAdminGuard]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
path: 'manager',
|
|
93
|
+
component: ManagerComponent,
|
|
94
|
+
canActivate: [MedHassoRoleGuard],
|
|
95
|
+
data: { roles: ['manager', 'admin'] }
|
|
96
|
+
}
|
|
97
|
+
];
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 3. Use in Components
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { Component } from '@angular/core';
|
|
104
|
+
import { MedHassoAuthService } from '@medha-analytics/medhasso-auth';
|
|
105
|
+
|
|
106
|
+
@Component({
|
|
107
|
+
selector: 'app-user-profile',
|
|
108
|
+
template: `
|
|
109
|
+
<div *ngIf="authService.isAuthenticated()">
|
|
110
|
+
<h2>Welcome, {{ authService.getUserDisplayName() }}!</h2>
|
|
111
|
+
<p>Email: {{ authService.getUserEmail() }}</p>
|
|
112
|
+
<div *ngIf="authService.isAdmin()">
|
|
113
|
+
<button>Admin Panel</button>
|
|
114
|
+
</div>
|
|
115
|
+
<button (click)="logout()">Logout</button>
|
|
116
|
+
</div>
|
|
117
|
+
`
|
|
118
|
+
})
|
|
119
|
+
export class UserProfileComponent {
|
|
120
|
+
constructor(public authService: MedHassoAuthService) {}
|
|
121
|
+
|
|
122
|
+
logout() {
|
|
123
|
+
this.authService.logout();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Configuration Options
|
|
129
|
+
|
|
130
|
+
### Environment Setup
|
|
131
|
+
First, configure your environment files:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// src/environments/environment.ts
|
|
135
|
+
export const environment = {
|
|
136
|
+
production: false,
|
|
137
|
+
ssoUrl: 'https://your-dev-sso.domain.com:3000',
|
|
138
|
+
refreshUrl: 'https://your-dev-refresh.domain.com:4000',
|
|
139
|
+
// ... other config
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// src/environments/environment.production.ts
|
|
143
|
+
export const environment = {
|
|
144
|
+
production: true,
|
|
145
|
+
ssoUrl: 'https://your-prod-sso.domain.com:3000',
|
|
146
|
+
refreshUrl: 'https://your-prod-refresh.domain.com:4000',
|
|
147
|
+
// ... other config
|
|
148
|
+
};
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Basic Configuration
|
|
152
|
+
```typescript
|
|
153
|
+
{
|
|
154
|
+
ssoUrl: environment.ssoUrl,
|
|
155
|
+
refreshUrl: environment.refreshUrl,
|
|
156
|
+
applicationName: 'Your Application Name'
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Advanced Configuration
|
|
161
|
+
```typescript
|
|
162
|
+
{
|
|
163
|
+
ssoUrl: environment.ssoUrl,
|
|
164
|
+
refreshUrl: environment.refreshUrl,
|
|
165
|
+
applicationName: 'Your Application Name',
|
|
166
|
+
|
|
167
|
+
// Token configuration
|
|
168
|
+
tokenConfig: {
|
|
169
|
+
storageType: 'localStorage', // or 'sessionStorage'
|
|
170
|
+
idTokenKey: 'idToken',
|
|
171
|
+
refreshTokenKey: 'refreshToken',
|
|
172
|
+
refreshBeforeExpiryMinutes: 5,
|
|
173
|
+
autoRefresh: true
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
// HTTP Interceptor configuration
|
|
177
|
+
interceptorConfig: {
|
|
178
|
+
enabled: true,
|
|
179
|
+
authHeaderPrefix: 'Bearer',
|
|
180
|
+
excludeUrls: ['*/public/*', '*/assets/*'],
|
|
181
|
+
includeUrls: ['*/api/*'] // Optional: if specified, only these URLs get tokens
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
// Security configuration
|
|
185
|
+
securityConfig: {
|
|
186
|
+
httpsOnly: true,
|
|
187
|
+
secureCookies: true,
|
|
188
|
+
additionalCspSources: ['https://your-cdn.com']
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Guards
|
|
194
|
+
|
|
195
|
+
### MedHassoAuthGuard
|
|
196
|
+
Basic authentication guard that ensures user is logged in.
|
|
197
|
+
|
|
198
|
+
### MedHassoRoleGuard
|
|
199
|
+
Role-based access guard. Use with route data:
|
|
200
|
+
```typescript
|
|
201
|
+
{
|
|
202
|
+
path: 'admin',
|
|
203
|
+
component: AdminComponent,
|
|
204
|
+
canActivate: [MedHassoRoleGuard],
|
|
205
|
+
data: {
|
|
206
|
+
role: 'admin', // Single role
|
|
207
|
+
roles: ['admin', 'manager'] // Multiple roles (OR condition)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### MedHassoAdminGuard
|
|
213
|
+
Admin-only access guard.
|
|
214
|
+
|
|
215
|
+
## Services
|
|
216
|
+
|
|
217
|
+
### MedHassoAuthService
|
|
218
|
+
Main authentication service with methods:
|
|
219
|
+
- `isAuthenticated(): boolean`
|
|
220
|
+
- `getCurrentUser(): MedHassoUser | null`
|
|
221
|
+
- `hasRole(role: string): boolean`
|
|
222
|
+
- `isAdmin(): boolean`
|
|
223
|
+
- `login(returnUrl?: string): void`
|
|
224
|
+
- `logout(): void`
|
|
225
|
+
- `getUserEmail(): string | null`
|
|
226
|
+
- `getUserDisplayName(): string | null`
|
|
227
|
+
|
|
228
|
+
### TokenManagementService
|
|
229
|
+
Low-level token management (usually not needed directly):
|
|
230
|
+
- `getTokenInfo(): TokenInfo | null`
|
|
231
|
+
- `refreshToken(): Observable<any>`
|
|
232
|
+
- `setTokens(idToken: string, refreshToken?: string): void`
|
|
233
|
+
|
|
234
|
+
## Environment-Specific Setup
|
|
235
|
+
|
|
236
|
+
### Development
|
|
237
|
+
```typescript
|
|
238
|
+
// src/environments/environment.ts
|
|
239
|
+
export const environment = {
|
|
240
|
+
production: false,
|
|
241
|
+
ssoUrl: 'https://dev-sso.your-domain.com:3000',
|
|
242
|
+
refreshUrl: 'https://dev-refresh.your-domain.com:4000'
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Usage in module/config
|
|
246
|
+
MedHassoAuthModule.forRoot({
|
|
247
|
+
ssoUrl: environment.ssoUrl,
|
|
248
|
+
refreshUrl: environment.refreshUrl,
|
|
249
|
+
applicationName: 'Your App (Dev)'
|
|
250
|
+
})
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Production
|
|
254
|
+
```typescript
|
|
255
|
+
// src/environments/environment.production.ts
|
|
256
|
+
export const environment = {
|
|
257
|
+
production: true,
|
|
258
|
+
ssoUrl: 'https://sso.your-domain.com:3000',
|
|
259
|
+
refreshUrl: 'https://refresh.your-domain.com:4000'
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// Usage in module/config
|
|
263
|
+
MedHassoAuthModule.forRoot({
|
|
264
|
+
ssoUrl: environment.ssoUrl,
|
|
265
|
+
refreshUrl: environment.refreshUrl,
|
|
266
|
+
applicationName: 'Your App'
|
|
267
|
+
})
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## CSP Configuration
|
|
271
|
+
|
|
272
|
+
For server-side Content Security Policy, include these domains:
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
// In your server configuration (e.g., Express.js)
|
|
276
|
+
const cspSources = [
|
|
277
|
+
process.env.SSO_URL || 'https://your-sso.domain.com:3000',
|
|
278
|
+
process.env.REFRESH_URL || 'https://your-refresh.domain.com:4000'
|
|
279
|
+
];
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Migration Guide
|
|
283
|
+
|
|
284
|
+
### From Custom Implementation
|
|
285
|
+
1. Remove your existing auth guard, interceptor, and token service
|
|
286
|
+
2. Install this library
|
|
287
|
+
3. Update your imports and module configuration
|
|
288
|
+
4. Update route guards to use library guards
|
|
289
|
+
5. Update components to use `MedHassoAuthService`
|
|
290
|
+
|
|
291
|
+
## Contributing
|
|
292
|
+
|
|
293
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
294
|
+
|
|
295
|
+
## License
|
|
296
|
+
|
|
297
297
|
MIT License - see [LICENSE](LICENSE) file for details.
|
|
@@ -3,7 +3,7 @@ import { InjectionToken, Inject, Injectable, NgModule } from '@angular/core';
|
|
|
3
3
|
import * as i1 from '@angular/common/http';
|
|
4
4
|
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
5
5
|
import { BehaviorSubject, timer, throwError, of } from 'rxjs';
|
|
6
|
-
import { tap, catchError,
|
|
6
|
+
import { tap, catchError, finalize, shareReplay, map, switchMap } from 'rxjs/operators';
|
|
7
7
|
import * as i2 from '@angular/router';
|
|
8
8
|
|
|
9
9
|
const MEDHASSO_CONFIG = new InjectionToken('MEDHASSO_CONFIG');
|
|
@@ -30,11 +30,44 @@ class TokenManagementService {
|
|
|
30
30
|
constructor(config, http) {
|
|
31
31
|
this.config = config;
|
|
32
32
|
this.http = http;
|
|
33
|
+
this.refreshInProgress$ = null;
|
|
33
34
|
this.tokenSubject = new BehaviorSubject(null);
|
|
34
35
|
this.userSubject = new BehaviorSubject(null);
|
|
36
|
+
this.onVisibilityChange = () => {
|
|
37
|
+
if (document.visibilityState === 'visible') {
|
|
38
|
+
this.ensureValidToken().subscribe();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
this.onWindowFocus = () => {
|
|
42
|
+
this.ensureValidToken().subscribe();
|
|
43
|
+
};
|
|
35
44
|
this.token$ = this.tokenSubject.asObservable();
|
|
36
45
|
this.user$ = this.userSubject.asObservable();
|
|
37
46
|
this.initializeFromStorage();
|
|
47
|
+
this.setupWakeDetection();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Re-validate the token whenever the tab regains focus/visibility.
|
|
51
|
+
* The refresh timer is a JS timer and does not fire while the OS/browser
|
|
52
|
+
* was suspended (e.g. laptop sleep overnight), so it can't be relied on
|
|
53
|
+
* alone to catch a token that went stale while the app was inactive.
|
|
54
|
+
*/
|
|
55
|
+
setupWakeDetection() {
|
|
56
|
+
if (typeof document === 'undefined' || typeof window === 'undefined') {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
document.addEventListener('visibilitychange', this.onVisibilityChange);
|
|
60
|
+
window.addEventListener('focus', this.onWindowFocus);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Remove wake-detection listeners registered in setupWakeDetection().
|
|
64
|
+
*/
|
|
65
|
+
teardownWakeDetection() {
|
|
66
|
+
if (typeof document === 'undefined' || typeof window === 'undefined') {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
|
70
|
+
window.removeEventListener('focus', this.onWindowFocus);
|
|
38
71
|
}
|
|
39
72
|
/**
|
|
40
73
|
* Initialize token information from storage
|
|
@@ -50,6 +83,30 @@ class TokenManagementService {
|
|
|
50
83
|
}
|
|
51
84
|
}
|
|
52
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Re-sync in-memory token state from storage if it has drifted (e.g.
|
|
88
|
+
* something wrote tokens directly to storage without going through
|
|
89
|
+
* setTokens()). No-op when storage already matches memory.
|
|
90
|
+
*/
|
|
91
|
+
syncFromStorage() {
|
|
92
|
+
const storedToken = this.getStoredToken();
|
|
93
|
+
const currentToken = this.getTokenInfo()?.token ?? null;
|
|
94
|
+
if (storedToken === currentToken) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!storedToken) {
|
|
98
|
+
this.tokenSubject.next(null);
|
|
99
|
+
this.userSubject.next(null);
|
|
100
|
+
this.clearTokenRefreshInterval();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const tokenInfo = this.createTokenInfo(storedToken);
|
|
104
|
+
this.tokenSubject.next(tokenInfo);
|
|
105
|
+
this.userSubject.next(this.extractUserFromToken(storedToken));
|
|
106
|
+
if (this.autoRefresh && !tokenInfo.isExpired) {
|
|
107
|
+
this.setTokenRefreshInterval(tokenInfo);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
53
110
|
/**
|
|
54
111
|
* Get stored token from configured storage
|
|
55
112
|
*/
|
|
@@ -202,14 +259,20 @@ class TokenManagementService {
|
|
|
202
259
|
}
|
|
203
260
|
}
|
|
204
261
|
/**
|
|
205
|
-
* Refresh the current token
|
|
262
|
+
* Refresh the current token.
|
|
263
|
+
* Concurrent callers (auto-refresh timer, wake detection, interceptor,
|
|
264
|
+
* route guard) share the same in-flight request instead of each firing
|
|
265
|
+
* their own POST to the refresh endpoint.
|
|
206
266
|
*/
|
|
207
267
|
refreshToken() {
|
|
268
|
+
if (this.refreshInProgress$) {
|
|
269
|
+
return this.refreshInProgress$;
|
|
270
|
+
}
|
|
208
271
|
const refreshToken = this.getStoredRefreshToken();
|
|
209
272
|
if (!refreshToken) {
|
|
210
273
|
return throwError(() => new Error('No refresh token available'));
|
|
211
274
|
}
|
|
212
|
-
|
|
275
|
+
const request$ = this.http.post(`${this.config.refreshUrl}/api/refresh-token`, { refreshToken })
|
|
213
276
|
.pipe(tap((response) => {
|
|
214
277
|
if (response.id_token) {
|
|
215
278
|
this.setTokens(response.id_token, response.refresh_token);
|
|
@@ -218,7 +281,49 @@ class TokenManagementService {
|
|
|
218
281
|
console.error('Token refresh failed:', error);
|
|
219
282
|
this.logout();
|
|
220
283
|
return throwError(() => error);
|
|
221
|
-
}))
|
|
284
|
+
}), finalize(() => {
|
|
285
|
+
this.refreshInProgress$ = null;
|
|
286
|
+
}), shareReplay({ bufferSize: 1, refCount: false }));
|
|
287
|
+
this.refreshInProgress$ = request$;
|
|
288
|
+
return request$;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Ensure the current token is valid, refreshing it first if it is
|
|
292
|
+
* expired. Resolves `false` if there is no token at all, or the token
|
|
293
|
+
* is expired and refreshing it failed (in both cases the caller should
|
|
294
|
+
* redirect to SSO).
|
|
295
|
+
*
|
|
296
|
+
* A token that merely `needsRefresh` (inside the refresh window, but
|
|
297
|
+
* not yet expired) is still good enough to use: the refresh for it is
|
|
298
|
+
* kicked off in the background so the *current* request/route isn't
|
|
299
|
+
* blocked or logged out by a transient refresh failure (network blip,
|
|
300
|
+
* refresh endpoint hiccup) while the existing token would have worked
|
|
301
|
+
* fine. Only an actually-expired token blocks the caller.
|
|
302
|
+
*
|
|
303
|
+
* Re-syncs from storage first: the in-memory token snapshot is only
|
|
304
|
+
* updated via setTokens()/logout(), so if something wrote directly to
|
|
305
|
+
* storage (e.g. the SSO callback flow) without going through this
|
|
306
|
+
* service, the in-memory copy would otherwise be stale until the next
|
|
307
|
+
* full page load re-runs initializeFromStorage().
|
|
308
|
+
*
|
|
309
|
+
* Anonymous/bootstrap endpoints that must be reachable before any token
|
|
310
|
+
* exists (e.g. the SSO callback's own token-exchange request) should be
|
|
311
|
+
* added to `interceptorConfig.excludeUrls` so they bypass this check
|
|
312
|
+
* entirely, rather than relying on this method to let them through.
|
|
313
|
+
*/
|
|
314
|
+
ensureValidToken() {
|
|
315
|
+
this.syncFromStorage();
|
|
316
|
+
const tokenInfo = this.getTokenInfo();
|
|
317
|
+
if (!tokenInfo) {
|
|
318
|
+
return of(false);
|
|
319
|
+
}
|
|
320
|
+
if (tokenInfo.isExpired) {
|
|
321
|
+
return this.refreshToken().pipe(map(() => true), catchError(() => of(false)));
|
|
322
|
+
}
|
|
323
|
+
if (tokenInfo.needsRefresh) {
|
|
324
|
+
this.refreshToken().subscribe({ error: () => { } });
|
|
325
|
+
}
|
|
326
|
+
return of(true);
|
|
222
327
|
}
|
|
223
328
|
/**
|
|
224
329
|
* Logout user and clear all tokens
|
|
@@ -263,6 +368,7 @@ class TokenManagementService {
|
|
|
263
368
|
*/
|
|
264
369
|
ngOnDestroy() {
|
|
265
370
|
this.clearTokenRefreshInterval();
|
|
371
|
+
this.teardownWakeDetection();
|
|
266
372
|
}
|
|
267
373
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TokenManagementService, deps: [{ token: MEDHASSO_CONFIG }, { token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
268
374
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TokenManagementService, providedIn: 'root' }); }
|
|
@@ -295,18 +401,27 @@ class MedHassoAuthInterceptor {
|
|
|
295
401
|
if (!this.shouldIncludeRequest(request)) {
|
|
296
402
|
return next.handle(request);
|
|
297
403
|
}
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
404
|
+
// Proactively ensure the token is valid (refreshing first if it's
|
|
405
|
+
// expired or within the refresh window) before attaching the header.
|
|
406
|
+
// This avoids sending a guaranteed-401 request after the app has been
|
|
407
|
+
// idle/suspended long enough for the in-memory refresh timer to miss it.
|
|
408
|
+
return this.tokenService.ensureValidToken().pipe(switchMap(valid => {
|
|
409
|
+
if (!valid) {
|
|
410
|
+
this.redirectToSSO();
|
|
411
|
+
return throwError(() => new Error('Authentication required'));
|
|
304
412
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
413
|
+
const modifiedRequest = this.addAuthorizationHeader(request);
|
|
414
|
+
return next.handle(modifiedRequest).pipe(catchError((error) => {
|
|
415
|
+
// Handle 401 Unauthorized errors
|
|
416
|
+
if (error.status === 401) {
|
|
417
|
+
return this.handle401Error(request, next);
|
|
418
|
+
}
|
|
419
|
+
// Handle 403 Forbidden errors
|
|
420
|
+
if (error.status === 403) {
|
|
421
|
+
console.warn('MedHasso Auth: Access forbidden (403)', error);
|
|
422
|
+
}
|
|
423
|
+
return throwError(() => error);
|
|
424
|
+
}));
|
|
310
425
|
}));
|
|
311
426
|
}
|
|
312
427
|
/**
|
|
@@ -672,16 +787,19 @@ class MedHassoAuthGuard {
|
|
|
672
787
|
if (this.handleAuthCallback(route)) {
|
|
673
788
|
return of(true);
|
|
674
789
|
}
|
|
675
|
-
//
|
|
676
|
-
|
|
677
|
-
|
|
790
|
+
// Re-syncs from storage and refreshes a stale/expired token before
|
|
791
|
+
// deciding, so this guard shares the same de-duplicated refresh and
|
|
792
|
+
// storage-drift handling as the HTTP interceptor.
|
|
793
|
+
return this.tokenService.ensureValidToken().pipe(map(valid => {
|
|
794
|
+
if (!valid) {
|
|
678
795
|
this.tokenService.redirectToSSO();
|
|
679
|
-
return
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
796
|
+
return false;
|
|
797
|
+
}
|
|
798
|
+
return true;
|
|
799
|
+
}), catchError(() => {
|
|
800
|
+
this.tokenService.redirectToSSO();
|
|
801
|
+
return of(false);
|
|
802
|
+
}));
|
|
685
803
|
}
|
|
686
804
|
/**
|
|
687
805
|
* Handle authentication callback from MedHasso SSO
|
|
@@ -704,16 +822,6 @@ class MedHassoAuthGuard {
|
|
|
704
822
|
}
|
|
705
823
|
return false;
|
|
706
824
|
}
|
|
707
|
-
/**
|
|
708
|
-
* Refresh token if needed
|
|
709
|
-
*/
|
|
710
|
-
refreshTokenIfNeeded() {
|
|
711
|
-
const tokenInfo = this.tokenService.getTokenInfo();
|
|
712
|
-
if (tokenInfo?.needsRefresh) {
|
|
713
|
-
return this.tokenService.refreshToken();
|
|
714
|
-
}
|
|
715
|
-
return of(null);
|
|
716
|
-
}
|
|
717
825
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthGuard, deps: [{ token: TokenManagementService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
718
826
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthGuard, providedIn: 'root' }); }
|
|
719
827
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"medha-analytics-medhasso-auth.mjs","sources":["../../../projects/medhasso-auth/src/lib/tokens/medhasso-config.token.ts","../../../projects/medhasso-auth/src/lib/services/token-management.service.ts","../../../projects/medhasso-auth/src/lib/interceptors/medhasso-auth.interceptor.ts","../../../projects/medhasso-auth/src/lib/services/medhasso-auth.service.ts","../../../projects/medhasso-auth/src/lib/medhasso-auth.module.ts","../../../projects/medhasso-auth/src/lib/guards/medhasso-auth.guard.ts","../../../projects/medhasso-auth/src/public-api.ts","../../../projects/medhasso-auth/src/medha-analytics-medhasso-auth.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { MedHassoConfig } from '../interfaces/medhasso-config.interface';\n\nexport const MEDHASSO_CONFIG = new InjectionToken<MedHassoConfig>('MEDHASSO_CONFIG');","import { Injectable, Inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { BehaviorSubject, Observable, throwError, timer } from 'rxjs';\nimport { catchError, tap } from 'rxjs/operators';\nimport { MedHassoConfig, TokenConfig, TokenInfo, MedHassoUser } from '../interfaces/medhasso-config.interface';\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class TokenManagementService {\n private refreshTokenInterval: any;\n private tokenSubject = new BehaviorSubject<TokenInfo | null>(null);\n private userSubject = new BehaviorSubject<MedHassoUser | null>(null);\n\n public token$ = this.tokenSubject.asObservable();\n public user$ = this.userSubject.asObservable();\n\n private get tokenConfig(): TokenConfig {\n return this.config.tokenConfig || {};\n }\n\n private get storageType(): 'localStorage' | 'sessionStorage' {\n return this.tokenConfig.storageType || 'localStorage';\n }\n\n private get idTokenKey(): string {\n return this.tokenConfig.idTokenKey || 'idToken';\n }\n\n private get refreshTokenKey(): string {\n return this.tokenConfig.refreshTokenKey || 'refreshToken';\n }\n\n private get refreshBeforeExpiryMinutes(): number {\n return this.tokenConfig.refreshBeforeExpiryMinutes || 5;\n }\n\n private get autoRefresh(): boolean {\n return this.tokenConfig.autoRefresh !== false;\n }\n\n constructor(\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\n private http: HttpClient\n ) {\n this.initializeFromStorage();\n }\n\n /**\n * Initialize token information from storage\n */\n private initializeFromStorage(): void {\n const token = this.getStoredToken();\n if (token) {\n const tokenInfo = this.createTokenInfo(token);\n this.tokenSubject.next(tokenInfo);\n this.userSubject.next(this.extractUserFromToken(token));\n \n if (this.autoRefresh && !tokenInfo.isExpired) {\n this.setTokenRefreshInterval(tokenInfo);\n }\n }\n }\n\n /**\n * Get stored token from configured storage\n */\n private getStoredToken(): string | null {\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\n return storage.getItem(this.idTokenKey);\n }\n\n /**\n * Get stored refresh token from configured storage\n */\n private getStoredRefreshToken(): string | null {\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\n return storage.getItem(this.refreshTokenKey);\n }\n\n /**\n * Store tokens in configured storage\n */\n private storeTokens(idToken: string, refreshToken?: string): void {\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\n storage.setItem(this.idTokenKey, idToken);\n if (refreshToken) {\n storage.setItem(this.refreshTokenKey, refreshToken);\n }\n }\n\n /**\n * Clear stored tokens\n */\n private clearStoredTokens(): void {\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\n storage.removeItem(this.idTokenKey);\n storage.removeItem(this.refreshTokenKey);\n }\n\n /**\n * Create token info object from JWT token\n */\n private createTokenInfo(token: string): TokenInfo {\n const payload = this.decodeJwt(token);\n const expiresAt = payload.exp * 1000; // Convert to milliseconds\n const now = Date.now();\n const refreshWindow = this.refreshBeforeExpiryMinutes * 60 * 1000;\n\n return {\n token,\n payload,\n expiresAt,\n isExpired: now >= expiresAt,\n needsRefresh: now >= (expiresAt - refreshWindow)\n };\n }\n\n /**\n * Decode JWT token payload\n */\n private decodeJwt(token: string): any {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n throw new Error('Invalid JWT token format');\n }\n const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));\n return payload;\n } catch (error) {\n console.error('Error decoding JWT token:', error);\n throw new Error('Invalid JWT token');\n }\n }\n\n /**\n * Extract user information from JWT token\n */\n private extractUserFromToken(token: string): MedHassoUser {\n const payload = this.decodeJwt(token);\n return {\n upn: payload.upn || payload.email,\n name: payload.name,\n roles: payload.roles || [],\n ...payload\n };\n }\n\n /**\n * Set up automatic token refresh interval\n */\n private setTokenRefreshInterval(tokenInfo: TokenInfo): void {\n this.clearTokenRefreshInterval();\n\n if (!this.autoRefresh || tokenInfo.isExpired) {\n return;\n }\n\n const remainingTime = tokenInfo.expiresAt - Date.now();\n const refreshTime = remainingTime - (this.refreshBeforeExpiryMinutes * 60 * 1000);\n\n if (refreshTime > 0) {\n this.refreshTokenInterval = timer(refreshTime).subscribe(() => {\n this.refreshToken().subscribe();\n });\n } else {\n // Token needs immediate refresh\n this.refreshToken().subscribe();\n }\n }\n\n /**\n * Clear token refresh interval\n */\n private clearTokenRefreshInterval(): void {\n if (this.refreshTokenInterval) {\n this.refreshTokenInterval.unsubscribe();\n this.refreshTokenInterval = null;\n }\n }\n\n /**\n * Get current token information\n */\n getTokenInfo(): TokenInfo | null {\n return this.tokenSubject.value;\n }\n\n /**\n * Get current user information\n */\n getCurrentUser(): MedHassoUser | null {\n return this.userSubject.value;\n }\n\n /**\n * Check if user is authenticated\n */\n isAuthenticated(): boolean {\n const tokenInfo = this.getTokenInfo();\n return tokenInfo !== null && !tokenInfo.isExpired;\n }\n\n /**\n * Check if user has specific role\n */\n hasRole(role: string): boolean {\n const user = this.getCurrentUser();\n return user?.roles?.includes(role) || false;\n }\n\n /**\n * Check if user is admin\n */\n isAdmin(): boolean {\n return this.hasRole('admin') || this.hasRole('administrator');\n }\n\n /**\n * Set tokens (typically called after successful authentication)\n */\n setTokens(idToken: string, refreshToken?: string): void {\n this.storeTokens(idToken, refreshToken);\n const tokenInfo = this.createTokenInfo(idToken);\n const user = this.extractUserFromToken(idToken);\n\n this.tokenSubject.next(tokenInfo);\n this.userSubject.next(user);\n\n if (this.autoRefresh) {\n this.setTokenRefreshInterval(tokenInfo);\n }\n }\n\n /**\n * Refresh the current token\n */\n refreshToken(): Observable<any> {\n const refreshToken = this.getStoredRefreshToken();\n \n if (!refreshToken) {\n return throwError(() => new Error('No refresh token available'));\n }\n\n return this.http.post(`${this.config.refreshUrl}/api/refresh-token`, { refreshToken })\n .pipe(\n tap((response: any) => {\n if (response.id_token) {\n this.setTokens(response.id_token, response.refresh_token);\n }\n }),\n catchError(error => {\n console.error('Token refresh failed:', error);\n this.logout();\n return throwError(() => error);\n })\n );\n }\n\n /**\n * Logout user and clear all tokens\n */\n logout(): void {\n this.clearTokenRefreshInterval();\n this.clearStoredTokens();\n this.tokenSubject.next(null);\n this.userSubject.next(null);\n }\n\n /**\n * Redirect to MedHasso SSO for authentication\n */\n redirectToSSO(returnUrl?: string): void {\n const currentUrl = returnUrl || window.location.href;\n const ssoUrl = `${this.config.ssoUrl}?url=${encodeURIComponent(currentUrl)}&applicationName=${encodeURIComponent(this.config.applicationName)}`;\n window.location.href = ssoUrl;\n }\n\n /**\n * Handle authentication callback (typically from SSO redirect)\n */\n handleAuthCallback(params: { idToken?: string; refreshToken?: string }): boolean {\n if (params.idToken) {\n this.setTokens(params.idToken, params.refreshToken);\n return true;\n }\n return false;\n }\n\n /**\n * Get authorization header value\n */\n getAuthorizationHeader(): string | null {\n const tokenInfo = this.getTokenInfo();\n if (tokenInfo && !tokenInfo.isExpired) {\n const prefix = this.config.interceptorConfig?.authHeaderPrefix || 'Bearer';\n return `${prefix} ${tokenInfo.token}`;\n }\n return null;\n }\n\n /**\n * Cleanup on service destruction\n */\n ngOnDestroy(): void {\n this.clearTokenRefreshInterval();\n }\n}","import { Injectable, Inject } from '@angular/core';\nimport { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';\nimport { Observable, throwError } from 'rxjs';\nimport { catchError, switchMap } from 'rxjs/operators';\nimport { MedHassoConfig } from '../interfaces/medhasso-config.interface';\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\nimport { TokenManagementService } from '../services/token-management.service';\n\n@Injectable()\nexport class MedHassoAuthInterceptor implements HttpInterceptor {\n\n constructor(\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\n private tokenService: TokenManagementService\n ) {}\n\n intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\n // Check if interceptor is enabled\n if (this.config.interceptorConfig?.enabled === false) {\n return next.handle(request);\n }\n\n // Check if request should be excluded\n if (this.shouldExcludeRequest(request)) {\n return next.handle(request);\n }\n\n // Check if request should be included (if includeUrls is specified)\n if (!this.shouldIncludeRequest(request)) {\n return next.handle(request);\n }\n\n // Add authorization header\n const modifiedRequest = this.addAuthorizationHeader(request);\n\n return next.handle(modifiedRequest).pipe(\n catchError((error: HttpErrorResponse) => {\n // Handle 401 Unauthorized errors\n if (error.status === 401) {\n return this.handle401Error(request, next);\n }\n \n // Handle 403 Forbidden errors\n if (error.status === 403) {\n console.warn('MedHasso Auth: Access forbidden (403)', error);\n }\n\n return throwError(() => error);\n })\n );\n }\n\n /**\n * Check if request URL should be excluded from authentication\n */\n private shouldExcludeRequest(request: HttpRequest<any>): boolean {\n const excludeUrls = this.config.interceptorConfig?.excludeUrls || [];\n return excludeUrls.some(url => this.matchesUrl(request.url, url));\n }\n\n /**\n * Check if request URL should be included for authentication\n * If includeUrls is not specified, all requests are included (unless excluded)\n */\n private shouldIncludeRequest(request: HttpRequest<any>): boolean {\n const includeUrls = this.config.interceptorConfig?.includeUrls;\n \n // If no includeUrls specified, include all requests\n if (!includeUrls || includeUrls.length === 0) {\n return true;\n }\n\n // If includeUrls specified, only include matching requests\n return includeUrls.some(url => this.matchesUrl(request.url, url));\n }\n\n /**\n * Check if request URL matches the pattern\n */\n private matchesUrl(requestUrl: string, pattern: string): boolean {\n // Support wildcards and exact matches\n if (pattern.includes('*')) {\n const regex = new RegExp(pattern.replace(/\\*/g, '.*'));\n return regex.test(requestUrl);\n }\n \n return requestUrl.includes(pattern);\n }\n\n /**\n * Add authorization header to request\n */\n private addAuthorizationHeader(request: HttpRequest<any>): HttpRequest<any> {\n const authHeader = this.tokenService.getAuthorizationHeader();\n \n if (!authHeader) {\n return request;\n }\n\n return request.clone({\n setHeaders: {\n Authorization: authHeader\n }\n });\n }\n\n /**\n * Handle 401 Unauthorized errors by attempting token refresh\n */\n private handle401Error(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\n const tokenInfo = this.tokenService.getTokenInfo();\n \n // If no token or token is expired, redirect to SSO\n if (!tokenInfo || tokenInfo.isExpired) {\n this.redirectToSSO();\n return throwError(() => new Error('Authentication required'));\n }\n\n // If token exists but request failed, try to refresh\n return this.tokenService.refreshToken().pipe(\n switchMap(() => {\n // Retry the original request with new token\n const retryRequest = this.addAuthorizationHeader(request);\n return next.handle(retryRequest);\n }),\n catchError((refreshError) => {\n // If refresh fails, redirect to SSO\n console.error('MedHasso Auth: Token refresh failed', refreshError);\n this.redirectToSSO();\n return throwError(() => refreshError);\n })\n );\n }\n\n /**\n * Redirect to SSO for authentication\n */\n private redirectToSSO(): void {\n // Add a small delay to prevent multiple redirects\n setTimeout(() => {\n this.tokenService.redirectToSSO();\n }, 100);\n }\n}","import { Injectable, Inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Observable, of } from 'rxjs';\nimport { map, catchError } from 'rxjs/operators';\nimport { MedHassoConfig, MedHassoUser } from '../interfaces/medhasso-config.interface';\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\nimport { TokenManagementService } from './token-management.service';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class MedHassoAuthService {\n\n constructor(\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\n private tokenService: TokenManagementService,\n private http: HttpClient\n ) {}\n\n /**\n * Get current authentication status\n */\n isAuthenticated(): boolean {\n return this.tokenService.isAuthenticated();\n }\n\n /**\n * Get current user information\n */\n getCurrentUser(): MedHassoUser | null {\n return this.tokenService.getCurrentUser();\n }\n\n /**\n * Get current user as observable\n */\n getCurrentUser$(): Observable<MedHassoUser | null> {\n return this.tokenService.user$;\n }\n\n /**\n * Check if user has specific role\n */\n hasRole(role: string): boolean {\n return this.tokenService.hasRole(role);\n }\n\n /**\n * Check if user has any of the specified roles\n */\n hasAnyRole(roles: string[]): boolean {\n return roles.some(role => this.tokenService.hasRole(role));\n }\n\n /**\n * Check if user has all of the specified roles\n */\n hasAllRoles(roles: string[]): boolean {\n return roles.every(role => this.tokenService.hasRole(role));\n }\n\n /**\n * Check if user is admin\n */\n isAdmin(): boolean {\n return this.tokenService.isAdmin();\n }\n\n /**\n * Login user (redirect to SSO)\n */\n login(returnUrl?: string): void {\n this.tokenService.redirectToSSO(returnUrl);\n }\n\n /**\n * Logout user\n */\n logout(): void {\n this.tokenService.logout();\n }\n\n /**\n * Refresh authentication token\n */\n refreshToken(): Observable<any> {\n return this.tokenService.refreshToken();\n }\n\n /**\n * Check access permissions for a simple key (if applicable)\n */\n checkAccess(simpleKey: string, backendUrl?: string): Observable<any> {\n const url = backendUrl || this.getBackendUrl();\n if (!url) {\n return of(null);\n }\n\n return this.http.get(`${url}/auth/guard?simple_key=${simpleKey}`)\n .pipe(\n catchError(error => {\n console.error('Access check failed:', error);\n return of(null);\n })\n );\n }\n\n /**\n * Check if user is admin via backend API (if applicable)\n */\n checkIsAdmin(backendUrl?: string): Observable<boolean> {\n const user = this.getCurrentUser();\n const url = backendUrl || this.getBackendUrl();\n \n if (!user?.upn || !url) {\n return of(false);\n }\n\n return this.http.get(`${url}/isAdmin?email=${user.upn}`)\n .pipe(\n map((response: any) => !!response),\n catchError(() => of(false))\n );\n }\n\n /**\n * Get backend URL from config (helper method)\n */\n private getBackendUrl(): string | null {\n // This would need to be configured or passed in\n // For now, return null as it's application-specific\n return null;\n }\n\n /**\n * Get token information\n */\n getTokenInfo() {\n return this.tokenService.getTokenInfo();\n }\n\n /**\n * Get token as observable\n */\n getToken$() {\n return this.tokenService.token$;\n }\n\n /**\n * Handle authentication callback\n */\n handleAuthCallback(params: { idToken?: string; refreshToken?: string }): boolean {\n return this.tokenService.handleAuthCallback(params);\n }\n\n /**\n * Get user email\n */\n getUserEmail(): string | null {\n return this.getCurrentUser()?.upn || null;\n }\n\n /**\n * Get user display name\n */\n getUserDisplayName(): string | null {\n return this.getCurrentUser()?.name || null;\n }\n\n /**\n * Get all user roles\n */\n getUserRoles(): string[] {\n return this.getCurrentUser()?.roles || [];\n }\n\n /**\n * Get authorization header value\n */\n getAuthorizationHeader(): string | null {\n return this.tokenService.getAuthorizationHeader();\n }\n}","import { NgModule, ModuleWithProviders, Provider } from '@angular/core';\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\nimport { MedHassoConfig } from './interfaces/medhasso-config.interface';\nimport { MEDHASSO_CONFIG } from './tokens/medhasso-config.token';\nimport { MedHassoAuthInterceptor } from './interceptors/medhasso-auth.interceptor';\nimport { TokenManagementService } from './services/token-management.service';\nimport { MedHassoAuthService } from './services/medhasso-auth.service';\n\n@NgModule({\n declarations: [],\n imports: [],\n exports: []\n})\nexport class MedHassoAuthModule {\n \n /**\n * Configure the MedHasso authentication module with required settings\n */\n static forRoot(config: MedHassoConfig): ModuleWithProviders<MedHassoAuthModule> {\n return {\n ngModule: MedHassoAuthModule,\n providers: [\n {\n provide: MEDHASSO_CONFIG,\n useValue: this.mergeWithDefaults(config)\n },\n TokenManagementService,\n MedHassoAuthService,\n {\n provide: HTTP_INTERCEPTORS,\n useClass: MedHassoAuthInterceptor,\n multi: true\n }\n ]\n };\n }\n\n /**\n * Configure the MedHasso authentication module for feature modules\n */\n static forChild(): ModuleWithProviders<MedHassoAuthModule> {\n return {\n ngModule: MedHassoAuthModule,\n providers: []\n };\n }\n\n /**\n * Provide MedHasso authentication with standalone components\n */\n static forStandalone(config: MedHassoConfig): Provider[] {\n return [\n {\n provide: MEDHASSO_CONFIG,\n useValue: this.mergeWithDefaults(config)\n },\n TokenManagementService,\n MedHassoAuthService,\n {\n provide: HTTP_INTERCEPTORS,\n useClass: MedHassoAuthInterceptor,\n multi: true\n }\n ];\n }\n\n /**\n * Merge user configuration with sensible defaults\n */\n private static mergeWithDefaults(config: MedHassoConfig): MedHassoConfig {\n const defaultConfig: Partial<MedHassoConfig> = {\n tokenConfig: {\n storageType: 'localStorage',\n idTokenKey: 'idToken',\n refreshTokenKey: 'refreshToken',\n refreshBeforeExpiryMinutes: 5,\n autoRefresh: true,\n ...config.tokenConfig\n },\n interceptorConfig: {\n enabled: true,\n authHeaderPrefix: 'Bearer',\n excludeUrls: [],\n includeUrls: [],\n ...config.interceptorConfig\n },\n securityConfig: {\n httpsOnly: true,\n secureCookies: true,\n additionalCspSources: [],\n ...config.securityConfig\n }\n };\n\n return {\n ...config,\n ...defaultConfig,\n tokenConfig: {\n ...defaultConfig.tokenConfig,\n ...config.tokenConfig\n },\n interceptorConfig: {\n ...defaultConfig.interceptorConfig,\n ...config.interceptorConfig\n },\n securityConfig: {\n ...defaultConfig.securityConfig,\n ...config.securityConfig\n }\n };\n }\n}","import { Injectable } from '@angular/core';\nimport { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, UrlTree } from '@angular/router';\nimport { Observable, of } from 'rxjs';\nimport { map, catchError } from 'rxjs/operators';\nimport { TokenManagementService } from '../services/token-management.service';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class MedHassoAuthGuard implements CanActivate, CanActivateChild {\n\n constructor(\n private tokenService: TokenManagementService,\n private router: Router\n ) {}\n\n canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\n return this.checkAuthentication(route);\n }\n\n canActivateChild(childRoute: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\n return this.checkAuthentication(childRoute);\n }\n\n private checkAuthentication(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> {\n // Check for authentication callback parameters\n if (this.handleAuthCallback(route)) {\n return of(true);\n }\n\n // Check if user is already authenticated\n if (this.tokenService.isAuthenticated()) {\n return this.refreshTokenIfNeeded().pipe(\n map(() => true),\n catchError(() => {\n this.tokenService.redirectToSSO();\n return of(false);\n })\n );\n }\n\n // Not authenticated, redirect to SSO\n this.tokenService.redirectToSSO();\n return of(false);\n }\n\n /**\n * Handle authentication callback from MedHasso SSO\n */\n private handleAuthCallback(route: ActivatedRouteSnapshot): boolean {\n const queryParams = route.queryParams;\n \n // Check for AIRO redirect flow\n if (queryParams['redirectapp'] === 'airo' && queryParams['idToken']) {\n return this.tokenService.handleAuthCallback({\n idToken: queryParams['idToken'],\n refreshToken: queryParams['refreshToken']\n });\n }\n\n // Check for standard authentication callback\n if (queryParams['idToken'] || queryParams['token']) {\n return this.tokenService.handleAuthCallback({\n idToken: queryParams['idToken'] || queryParams['token'],\n refreshToken: queryParams['refreshToken']\n });\n }\n\n return false;\n }\n\n /**\n * Refresh token if needed\n */\n private refreshTokenIfNeeded(): Observable<any> {\n const tokenInfo = this.tokenService.getTokenInfo();\n \n if (tokenInfo?.needsRefresh) {\n return this.tokenService.refreshToken();\n }\n\n return of(null);\n }\n}\n\n/**\n * Role-based authentication guard\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class MedHassoRoleGuard implements CanActivate, CanActivateChild {\n\n constructor(\n private tokenService: TokenManagementService,\n private router: Router\n ) {}\n\n canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\n return this.checkRole(route);\n }\n\n canActivateChild(childRoute: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\n return this.checkRole(childRoute);\n }\n\n private checkRole(route: ActivatedRouteSnapshot): boolean | UrlTree {\n const requiredRoles = route.data['roles'] as string[];\n const requiredRole = route.data['role'] as string;\n\n if (!this.tokenService.isAuthenticated()) {\n this.tokenService.redirectToSSO();\n return false;\n }\n\n // Check multiple roles (OR condition)\n if (requiredRoles && requiredRoles.length > 0) {\n const hasAnyRole = requiredRoles.some(role => this.tokenService.hasRole(role));\n if (!hasAnyRole) {\n return this.router.createUrlTree(['/unauthorized']);\n }\n }\n\n // Check single role\n if (requiredRole && !this.tokenService.hasRole(requiredRole)) {\n return this.router.createUrlTree(['/unauthorized']);\n }\n\n return true;\n }\n}\n\n/**\n * Admin-only authentication guard\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class MedHassoAdminGuard implements CanActivate, CanActivateChild {\n\n constructor(\n private tokenService: TokenManagementService,\n private router: Router\n ) {}\n\n canActivate(): boolean | UrlTree {\n return this.checkAdmin();\n }\n\n canActivateChild(): boolean | UrlTree {\n return this.checkAdmin();\n }\n\n private checkAdmin(): boolean | UrlTree {\n if (!this.tokenService.isAuthenticated()) {\n this.tokenService.redirectToSSO();\n return false;\n }\n\n if (!this.tokenService.isAdmin()) {\n return this.router.createUrlTree(['/unauthorized']);\n }\n\n return true;\n }\n}","/*\n * Public API Surface of medhasso-auth\n */\n\n// Module\nexport * from './lib/medhasso-auth.module';\n\n// Services\nexport * from './lib/services/token-management.service';\nexport * from './lib/services/medhasso-auth.service';\n\n// Guards\nexport * from './lib/guards/medhasso-auth.guard';\n\n// Interceptors\nexport * from './lib/interceptors/medhasso-auth.interceptor';\n\n// Interfaces\nexport * from './lib/interfaces/medhasso-config.interface';\n\n// Tokens\nexport * from './lib/tokens/medhasso-config.token';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.TokenManagementService","i2"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"medha-analytics-medhasso-auth.mjs","sources":["../../../projects/medhasso-auth/src/lib/tokens/medhasso-config.token.ts","../../../projects/medhasso-auth/src/lib/services/token-management.service.ts","../../../projects/medhasso-auth/src/lib/interceptors/medhasso-auth.interceptor.ts","../../../projects/medhasso-auth/src/lib/services/medhasso-auth.service.ts","../../../projects/medhasso-auth/src/lib/medhasso-auth.module.ts","../../../projects/medhasso-auth/src/lib/guards/medhasso-auth.guard.ts","../../../projects/medhasso-auth/src/public-api.ts","../../../projects/medhasso-auth/src/medha-analytics-medhasso-auth.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\nimport { MedHassoConfig } from '../interfaces/medhasso-config.interface';\r\n\r\nexport const MEDHASSO_CONFIG = new InjectionToken<MedHassoConfig>('MEDHASSO_CONFIG');","import { Injectable, Inject } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { BehaviorSubject, Observable, of, throwError, timer } from 'rxjs';\r\nimport { catchError, finalize, map, shareReplay, tap } from 'rxjs/operators';\r\nimport { MedHassoConfig, TokenConfig, TokenInfo, MedHassoUser } from '../interfaces/medhasso-config.interface';\r\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class TokenManagementService {\r\n private refreshTokenInterval: any;\r\n private refreshInProgress$: Observable<any> | null = null;\r\n private tokenSubject = new BehaviorSubject<TokenInfo | null>(null);\r\n private userSubject = new BehaviorSubject<MedHassoUser | null>(null);\r\n private readonly onVisibilityChange = () => {\r\n if (document.visibilityState === 'visible') {\r\n this.ensureValidToken().subscribe();\r\n }\r\n };\r\n private readonly onWindowFocus = () => {\r\n this.ensureValidToken().subscribe();\r\n };\r\n\r\n public token$ = this.tokenSubject.asObservable();\r\n public user$ = this.userSubject.asObservable();\r\n\r\n private get tokenConfig(): TokenConfig {\r\n return this.config.tokenConfig || {};\r\n }\r\n\r\n private get storageType(): 'localStorage' | 'sessionStorage' {\r\n return this.tokenConfig.storageType || 'localStorage';\r\n }\r\n\r\n private get idTokenKey(): string {\r\n return this.tokenConfig.idTokenKey || 'idToken';\r\n }\r\n\r\n private get refreshTokenKey(): string {\r\n return this.tokenConfig.refreshTokenKey || 'refreshToken';\r\n }\r\n\r\n private get refreshBeforeExpiryMinutes(): number {\r\n return this.tokenConfig.refreshBeforeExpiryMinutes || 5;\r\n }\r\n\r\n private get autoRefresh(): boolean {\r\n return this.tokenConfig.autoRefresh !== false;\r\n }\r\n\r\n constructor(\r\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\r\n private http: HttpClient\r\n ) {\r\n this.initializeFromStorage();\r\n this.setupWakeDetection();\r\n }\r\n\r\n /**\r\n * Re-validate the token whenever the tab regains focus/visibility.\r\n * The refresh timer is a JS timer and does not fire while the OS/browser\r\n * was suspended (e.g. laptop sleep overnight), so it can't be relied on\r\n * alone to catch a token that went stale while the app was inactive.\r\n */\r\n private setupWakeDetection(): void {\r\n if (typeof document === 'undefined' || typeof window === 'undefined') {\r\n return;\r\n }\r\n\r\n document.addEventListener('visibilitychange', this.onVisibilityChange);\r\n window.addEventListener('focus', this.onWindowFocus);\r\n }\r\n\r\n /**\r\n * Remove wake-detection listeners registered in setupWakeDetection().\r\n */\r\n private teardownWakeDetection(): void {\r\n if (typeof document === 'undefined' || typeof window === 'undefined') {\r\n return;\r\n }\r\n\r\n document.removeEventListener('visibilitychange', this.onVisibilityChange);\r\n window.removeEventListener('focus', this.onWindowFocus);\r\n }\r\n\r\n /**\r\n * Initialize token information from storage\r\n */\r\n private initializeFromStorage(): void {\r\n const token = this.getStoredToken();\r\n if (token) {\r\n const tokenInfo = this.createTokenInfo(token);\r\n this.tokenSubject.next(tokenInfo);\r\n this.userSubject.next(this.extractUserFromToken(token));\r\n \r\n if (this.autoRefresh && !tokenInfo.isExpired) {\r\n this.setTokenRefreshInterval(tokenInfo);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Re-sync in-memory token state from storage if it has drifted (e.g.\r\n * something wrote tokens directly to storage without going through\r\n * setTokens()). No-op when storage already matches memory.\r\n */\r\n private syncFromStorage(): void {\r\n const storedToken = this.getStoredToken();\r\n const currentToken = this.getTokenInfo()?.token ?? null;\r\n\r\n if (storedToken === currentToken) {\r\n return;\r\n }\r\n\r\n if (!storedToken) {\r\n this.tokenSubject.next(null);\r\n this.userSubject.next(null);\r\n this.clearTokenRefreshInterval();\r\n return;\r\n }\r\n\r\n const tokenInfo = this.createTokenInfo(storedToken);\r\n this.tokenSubject.next(tokenInfo);\r\n this.userSubject.next(this.extractUserFromToken(storedToken));\r\n\r\n if (this.autoRefresh && !tokenInfo.isExpired) {\r\n this.setTokenRefreshInterval(tokenInfo);\r\n }\r\n }\r\n\r\n /**\r\n * Get stored token from configured storage\r\n */\r\n private getStoredToken(): string | null {\r\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\r\n return storage.getItem(this.idTokenKey);\r\n }\r\n\r\n /**\r\n * Get stored refresh token from configured storage\r\n */\r\n private getStoredRefreshToken(): string | null {\r\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\r\n return storage.getItem(this.refreshTokenKey);\r\n }\r\n\r\n /**\r\n * Store tokens in configured storage\r\n */\r\n private storeTokens(idToken: string, refreshToken?: string): void {\r\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\r\n storage.setItem(this.idTokenKey, idToken);\r\n if (refreshToken) {\r\n storage.setItem(this.refreshTokenKey, refreshToken);\r\n }\r\n }\r\n\r\n /**\r\n * Clear stored tokens\r\n */\r\n private clearStoredTokens(): void {\r\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\r\n storage.removeItem(this.idTokenKey);\r\n storage.removeItem(this.refreshTokenKey);\r\n }\r\n\r\n /**\r\n * Create token info object from JWT token\r\n */\r\n private createTokenInfo(token: string): TokenInfo {\r\n const payload = this.decodeJwt(token);\r\n const expiresAt = payload.exp * 1000; // Convert to milliseconds\r\n const now = Date.now();\r\n const refreshWindow = this.refreshBeforeExpiryMinutes * 60 * 1000;\r\n\r\n return {\r\n token,\r\n payload,\r\n expiresAt,\r\n isExpired: now >= expiresAt,\r\n needsRefresh: now >= (expiresAt - refreshWindow)\r\n };\r\n }\r\n\r\n /**\r\n * Decode JWT token payload\r\n */\r\n private decodeJwt(token: string): any {\r\n try {\r\n const parts = token.split('.');\r\n if (parts.length !== 3) {\r\n throw new Error('Invalid JWT token format');\r\n }\r\n const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));\r\n return payload;\r\n } catch (error) {\r\n console.error('Error decoding JWT token:', error);\r\n throw new Error('Invalid JWT token');\r\n }\r\n }\r\n\r\n /**\r\n * Extract user information from JWT token\r\n */\r\n private extractUserFromToken(token: string): MedHassoUser {\r\n const payload = this.decodeJwt(token);\r\n return {\r\n upn: payload.upn || payload.email,\r\n name: payload.name,\r\n roles: payload.roles || [],\r\n ...payload\r\n };\r\n }\r\n\r\n /**\r\n * Set up automatic token refresh interval\r\n */\r\n private setTokenRefreshInterval(tokenInfo: TokenInfo): void {\r\n this.clearTokenRefreshInterval();\r\n\r\n if (!this.autoRefresh || tokenInfo.isExpired) {\r\n return;\r\n }\r\n\r\n const remainingTime = tokenInfo.expiresAt - Date.now();\r\n const refreshTime = remainingTime - (this.refreshBeforeExpiryMinutes * 60 * 1000);\r\n\r\n if (refreshTime > 0) {\r\n this.refreshTokenInterval = timer(refreshTime).subscribe(() => {\r\n this.refreshToken().subscribe();\r\n });\r\n } else {\r\n // Token needs immediate refresh\r\n this.refreshToken().subscribe();\r\n }\r\n }\r\n\r\n /**\r\n * Clear token refresh interval\r\n */\r\n private clearTokenRefreshInterval(): void {\r\n if (this.refreshTokenInterval) {\r\n this.refreshTokenInterval.unsubscribe();\r\n this.refreshTokenInterval = null;\r\n }\r\n }\r\n\r\n /**\r\n * Get current token information\r\n */\r\n getTokenInfo(): TokenInfo | null {\r\n return this.tokenSubject.value;\r\n }\r\n\r\n /**\r\n * Get current user information\r\n */\r\n getCurrentUser(): MedHassoUser | null {\r\n return this.userSubject.value;\r\n }\r\n\r\n /**\r\n * Check if user is authenticated\r\n */\r\n isAuthenticated(): boolean {\r\n const tokenInfo = this.getTokenInfo();\r\n return tokenInfo !== null && !tokenInfo.isExpired;\r\n }\r\n\r\n /**\r\n * Check if user has specific role\r\n */\r\n hasRole(role: string): boolean {\r\n const user = this.getCurrentUser();\r\n return user?.roles?.includes(role) || false;\r\n }\r\n\r\n /**\r\n * Check if user is admin\r\n */\r\n isAdmin(): boolean {\r\n return this.hasRole('admin') || this.hasRole('administrator');\r\n }\r\n\r\n /**\r\n * Set tokens (typically called after successful authentication)\r\n */\r\n setTokens(idToken: string, refreshToken?: string): void {\r\n this.storeTokens(idToken, refreshToken);\r\n const tokenInfo = this.createTokenInfo(idToken);\r\n const user = this.extractUserFromToken(idToken);\r\n\r\n this.tokenSubject.next(tokenInfo);\r\n this.userSubject.next(user);\r\n\r\n if (this.autoRefresh) {\r\n this.setTokenRefreshInterval(tokenInfo);\r\n }\r\n }\r\n\r\n /**\r\n * Refresh the current token.\r\n * Concurrent callers (auto-refresh timer, wake detection, interceptor,\r\n * route guard) share the same in-flight request instead of each firing\r\n * their own POST to the refresh endpoint.\r\n */\r\n refreshToken(): Observable<any> {\r\n if (this.refreshInProgress$) {\r\n return this.refreshInProgress$;\r\n }\r\n\r\n const refreshToken = this.getStoredRefreshToken();\r\n\r\n if (!refreshToken) {\r\n return throwError(() => new Error('No refresh token available'));\r\n }\r\n\r\n const request$ = this.http.post(`${this.config.refreshUrl}/api/refresh-token`, { refreshToken })\r\n .pipe(\r\n tap((response: any) => {\r\n if (response.id_token) {\r\n this.setTokens(response.id_token, response.refresh_token);\r\n }\r\n }),\r\n catchError(error => {\r\n console.error('Token refresh failed:', error);\r\n this.logout();\r\n return throwError(() => error);\r\n }),\r\n finalize(() => {\r\n this.refreshInProgress$ = null;\r\n }),\r\n shareReplay({ bufferSize: 1, refCount: false })\r\n );\r\n\r\n this.refreshInProgress$ = request$;\r\n return request$;\r\n }\r\n\r\n /**\r\n * Ensure the current token is valid, refreshing it first if it is\r\n * expired. Resolves `false` if there is no token at all, or the token\r\n * is expired and refreshing it failed (in both cases the caller should\r\n * redirect to SSO).\r\n *\r\n * A token that merely `needsRefresh` (inside the refresh window, but\r\n * not yet expired) is still good enough to use: the refresh for it is\r\n * kicked off in the background so the *current* request/route isn't\r\n * blocked or logged out by a transient refresh failure (network blip,\r\n * refresh endpoint hiccup) while the existing token would have worked\r\n * fine. Only an actually-expired token blocks the caller.\r\n *\r\n * Re-syncs from storage first: the in-memory token snapshot is only\r\n * updated via setTokens()/logout(), so if something wrote directly to\r\n * storage (e.g. the SSO callback flow) without going through this\r\n * service, the in-memory copy would otherwise be stale until the next\r\n * full page load re-runs initializeFromStorage().\r\n *\r\n * Anonymous/bootstrap endpoints that must be reachable before any token\r\n * exists (e.g. the SSO callback's own token-exchange request) should be\r\n * added to `interceptorConfig.excludeUrls` so they bypass this check\r\n * entirely, rather than relying on this method to let them through.\r\n */\r\n ensureValidToken(): Observable<boolean> {\r\n this.syncFromStorage();\r\n const tokenInfo = this.getTokenInfo();\r\n\r\n if (!tokenInfo) {\r\n return of(false);\r\n }\r\n\r\n if (tokenInfo.isExpired) {\r\n return this.refreshToken().pipe(\r\n map(() => true),\r\n catchError(() => of(false))\r\n );\r\n }\r\n\r\n if (tokenInfo.needsRefresh) {\r\n this.refreshToken().subscribe({ error: () => {} });\r\n }\r\n\r\n return of(true);\r\n }\r\n\r\n /**\r\n * Logout user and clear all tokens\r\n */\r\n logout(): void {\r\n this.clearTokenRefreshInterval();\r\n this.clearStoredTokens();\r\n this.tokenSubject.next(null);\r\n this.userSubject.next(null);\r\n }\r\n\r\n /**\r\n * Redirect to MedHasso SSO for authentication\r\n */\r\n redirectToSSO(returnUrl?: string): void {\r\n const currentUrl = returnUrl || window.location.href;\r\n const ssoUrl = `${this.config.ssoUrl}?url=${encodeURIComponent(currentUrl)}&applicationName=${encodeURIComponent(this.config.applicationName)}`;\r\n window.location.href = ssoUrl;\r\n }\r\n\r\n /**\r\n * Handle authentication callback (typically from SSO redirect)\r\n */\r\n handleAuthCallback(params: { idToken?: string; refreshToken?: string }): boolean {\r\n if (params.idToken) {\r\n this.setTokens(params.idToken, params.refreshToken);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Get authorization header value\r\n */\r\n getAuthorizationHeader(): string | null {\r\n const tokenInfo = this.getTokenInfo();\r\n if (tokenInfo && !tokenInfo.isExpired) {\r\n const prefix = this.config.interceptorConfig?.authHeaderPrefix || 'Bearer';\r\n return `${prefix} ${tokenInfo.token}`;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Cleanup on service destruction\r\n */\r\n ngOnDestroy(): void {\r\n this.clearTokenRefreshInterval();\r\n this.teardownWakeDetection();\r\n }\r\n}\r\n","import { Injectable, Inject } from '@angular/core';\r\nimport { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { catchError, switchMap } from 'rxjs/operators';\r\nimport { MedHassoConfig } from '../interfaces/medhasso-config.interface';\r\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\r\nimport { TokenManagementService } from '../services/token-management.service';\r\n\r\n@Injectable()\r\nexport class MedHassoAuthInterceptor implements HttpInterceptor {\r\n\r\n constructor(\r\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\r\n private tokenService: TokenManagementService\r\n ) {}\r\n\r\n intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\r\n // Check if interceptor is enabled\r\n if (this.config.interceptorConfig?.enabled === false) {\r\n return next.handle(request);\r\n }\r\n\r\n // Check if request should be excluded\r\n if (this.shouldExcludeRequest(request)) {\r\n return next.handle(request);\r\n }\r\n\r\n // Check if request should be included (if includeUrls is specified)\r\n if (!this.shouldIncludeRequest(request)) {\r\n return next.handle(request);\r\n }\r\n\r\n // Proactively ensure the token is valid (refreshing first if it's\r\n // expired or within the refresh window) before attaching the header.\r\n // This avoids sending a guaranteed-401 request after the app has been\r\n // idle/suspended long enough for the in-memory refresh timer to miss it.\r\n return this.tokenService.ensureValidToken().pipe(\r\n switchMap(valid => {\r\n if (!valid) {\r\n this.redirectToSSO();\r\n return throwError(() => new Error('Authentication required'));\r\n }\r\n\r\n const modifiedRequest = this.addAuthorizationHeader(request);\r\n\r\n return next.handle(modifiedRequest).pipe(\r\n catchError((error: HttpErrorResponse) => {\r\n // Handle 401 Unauthorized errors\r\n if (error.status === 401) {\r\n return this.handle401Error(request, next);\r\n }\r\n\r\n // Handle 403 Forbidden errors\r\n if (error.status === 403) {\r\n console.warn('MedHasso Auth: Access forbidden (403)', error);\r\n }\r\n\r\n return throwError(() => error);\r\n })\r\n );\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Check if request URL should be excluded from authentication\r\n */\r\n private shouldExcludeRequest(request: HttpRequest<any>): boolean {\r\n const excludeUrls = this.config.interceptorConfig?.excludeUrls || [];\r\n return excludeUrls.some(url => this.matchesUrl(request.url, url));\r\n }\r\n\r\n /**\r\n * Check if request URL should be included for authentication\r\n * If includeUrls is not specified, all requests are included (unless excluded)\r\n */\r\n private shouldIncludeRequest(request: HttpRequest<any>): boolean {\r\n const includeUrls = this.config.interceptorConfig?.includeUrls;\r\n \r\n // If no includeUrls specified, include all requests\r\n if (!includeUrls || includeUrls.length === 0) {\r\n return true;\r\n }\r\n\r\n // If includeUrls specified, only include matching requests\r\n return includeUrls.some(url => this.matchesUrl(request.url, url));\r\n }\r\n\r\n /**\r\n * Check if request URL matches the pattern\r\n */\r\n private matchesUrl(requestUrl: string, pattern: string): boolean {\r\n // Support wildcards and exact matches\r\n if (pattern.includes('*')) {\r\n const regex = new RegExp(pattern.replace(/\\*/g, '.*'));\r\n return regex.test(requestUrl);\r\n }\r\n \r\n return requestUrl.includes(pattern);\r\n }\r\n\r\n /**\r\n * Add authorization header to request\r\n */\r\n private addAuthorizationHeader(request: HttpRequest<any>): HttpRequest<any> {\r\n const authHeader = this.tokenService.getAuthorizationHeader();\r\n \r\n if (!authHeader) {\r\n return request;\r\n }\r\n\r\n return request.clone({\r\n setHeaders: {\r\n Authorization: authHeader\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Handle 401 Unauthorized errors by attempting token refresh\r\n */\r\n private handle401Error(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\r\n const tokenInfo = this.tokenService.getTokenInfo();\r\n \r\n // If no token or token is expired, redirect to SSO\r\n if (!tokenInfo || tokenInfo.isExpired) {\r\n this.redirectToSSO();\r\n return throwError(() => new Error('Authentication required'));\r\n }\r\n\r\n // If token exists but request failed, try to refresh\r\n return this.tokenService.refreshToken().pipe(\r\n switchMap(() => {\r\n // Retry the original request with new token\r\n const retryRequest = this.addAuthorizationHeader(request);\r\n return next.handle(retryRequest);\r\n }),\r\n catchError((refreshError) => {\r\n // If refresh fails, redirect to SSO\r\n console.error('MedHasso Auth: Token refresh failed', refreshError);\r\n this.redirectToSSO();\r\n return throwError(() => refreshError);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Redirect to SSO for authentication\r\n */\r\n private redirectToSSO(): void {\r\n // Add a small delay to prevent multiple redirects\r\n setTimeout(() => {\r\n this.tokenService.redirectToSSO();\r\n }, 100);\r\n }\r\n}","import { Injectable, Inject } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { Observable, of } from 'rxjs';\r\nimport { map, catchError } from 'rxjs/operators';\r\nimport { MedHassoConfig, MedHassoUser } from '../interfaces/medhasso-config.interface';\r\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\r\nimport { TokenManagementService } from './token-management.service';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class MedHassoAuthService {\r\n\r\n constructor(\r\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\r\n private tokenService: TokenManagementService,\r\n private http: HttpClient\r\n ) {}\r\n\r\n /**\r\n * Get current authentication status\r\n */\r\n isAuthenticated(): boolean {\r\n return this.tokenService.isAuthenticated();\r\n }\r\n\r\n /**\r\n * Get current user information\r\n */\r\n getCurrentUser(): MedHassoUser | null {\r\n return this.tokenService.getCurrentUser();\r\n }\r\n\r\n /**\r\n * Get current user as observable\r\n */\r\n getCurrentUser$(): Observable<MedHassoUser | null> {\r\n return this.tokenService.user$;\r\n }\r\n\r\n /**\r\n * Check if user has specific role\r\n */\r\n hasRole(role: string): boolean {\r\n return this.tokenService.hasRole(role);\r\n }\r\n\r\n /**\r\n * Check if user has any of the specified roles\r\n */\r\n hasAnyRole(roles: string[]): boolean {\r\n return roles.some(role => this.tokenService.hasRole(role));\r\n }\r\n\r\n /**\r\n * Check if user has all of the specified roles\r\n */\r\n hasAllRoles(roles: string[]): boolean {\r\n return roles.every(role => this.tokenService.hasRole(role));\r\n }\r\n\r\n /**\r\n * Check if user is admin\r\n */\r\n isAdmin(): boolean {\r\n return this.tokenService.isAdmin();\r\n }\r\n\r\n /**\r\n * Login user (redirect to SSO)\r\n */\r\n login(returnUrl?: string): void {\r\n this.tokenService.redirectToSSO(returnUrl);\r\n }\r\n\r\n /**\r\n * Logout user\r\n */\r\n logout(): void {\r\n this.tokenService.logout();\r\n }\r\n\r\n /**\r\n * Refresh authentication token\r\n */\r\n refreshToken(): Observable<any> {\r\n return this.tokenService.refreshToken();\r\n }\r\n\r\n /**\r\n * Check access permissions for a simple key (if applicable)\r\n */\r\n checkAccess(simpleKey: string, backendUrl?: string): Observable<any> {\r\n const url = backendUrl || this.getBackendUrl();\r\n if (!url) {\r\n return of(null);\r\n }\r\n\r\n return this.http.get(`${url}/auth/guard?simple_key=${simpleKey}`)\r\n .pipe(\r\n catchError(error => {\r\n console.error('Access check failed:', error);\r\n return of(null);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Check if user is admin via backend API (if applicable)\r\n */\r\n checkIsAdmin(backendUrl?: string): Observable<boolean> {\r\n const user = this.getCurrentUser();\r\n const url = backendUrl || this.getBackendUrl();\r\n \r\n if (!user?.upn || !url) {\r\n return of(false);\r\n }\r\n\r\n return this.http.get(`${url}/isAdmin?email=${user.upn}`)\r\n .pipe(\r\n map((response: any) => !!response),\r\n catchError(() => of(false))\r\n );\r\n }\r\n\r\n /**\r\n * Get backend URL from config (helper method)\r\n */\r\n private getBackendUrl(): string | null {\r\n // This would need to be configured or passed in\r\n // For now, return null as it's application-specific\r\n return null;\r\n }\r\n\r\n /**\r\n * Get token information\r\n */\r\n getTokenInfo() {\r\n return this.tokenService.getTokenInfo();\r\n }\r\n\r\n /**\r\n * Get token as observable\r\n */\r\n getToken$() {\r\n return this.tokenService.token$;\r\n }\r\n\r\n /**\r\n * Handle authentication callback\r\n */\r\n handleAuthCallback(params: { idToken?: string; refreshToken?: string }): boolean {\r\n return this.tokenService.handleAuthCallback(params);\r\n }\r\n\r\n /**\r\n * Get user email\r\n */\r\n getUserEmail(): string | null {\r\n return this.getCurrentUser()?.upn || null;\r\n }\r\n\r\n /**\r\n * Get user display name\r\n */\r\n getUserDisplayName(): string | null {\r\n return this.getCurrentUser()?.name || null;\r\n }\r\n\r\n /**\r\n * Get all user roles\r\n */\r\n getUserRoles(): string[] {\r\n return this.getCurrentUser()?.roles || [];\r\n }\r\n\r\n /**\r\n * Get authorization header value\r\n */\r\n getAuthorizationHeader(): string | null {\r\n return this.tokenService.getAuthorizationHeader();\r\n }\r\n}","import { NgModule, ModuleWithProviders, Provider } from '@angular/core';\r\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\r\nimport { MedHassoConfig } from './interfaces/medhasso-config.interface';\r\nimport { MEDHASSO_CONFIG } from './tokens/medhasso-config.token';\r\nimport { MedHassoAuthInterceptor } from './interceptors/medhasso-auth.interceptor';\r\nimport { TokenManagementService } from './services/token-management.service';\r\nimport { MedHassoAuthService } from './services/medhasso-auth.service';\r\n\r\n@NgModule({\r\n declarations: [],\r\n imports: [],\r\n exports: []\r\n})\r\nexport class MedHassoAuthModule {\r\n \r\n /**\r\n * Configure the MedHasso authentication module with required settings\r\n */\r\n static forRoot(config: MedHassoConfig): ModuleWithProviders<MedHassoAuthModule> {\r\n return {\r\n ngModule: MedHassoAuthModule,\r\n providers: [\r\n {\r\n provide: MEDHASSO_CONFIG,\r\n useValue: this.mergeWithDefaults(config)\r\n },\r\n TokenManagementService,\r\n MedHassoAuthService,\r\n {\r\n provide: HTTP_INTERCEPTORS,\r\n useClass: MedHassoAuthInterceptor,\r\n multi: true\r\n }\r\n ]\r\n };\r\n }\r\n\r\n /**\r\n * Configure the MedHasso authentication module for feature modules\r\n */\r\n static forChild(): ModuleWithProviders<MedHassoAuthModule> {\r\n return {\r\n ngModule: MedHassoAuthModule,\r\n providers: []\r\n };\r\n }\r\n\r\n /**\r\n * Provide MedHasso authentication with standalone components\r\n */\r\n static forStandalone(config: MedHassoConfig): Provider[] {\r\n return [\r\n {\r\n provide: MEDHASSO_CONFIG,\r\n useValue: this.mergeWithDefaults(config)\r\n },\r\n TokenManagementService,\r\n MedHassoAuthService,\r\n {\r\n provide: HTTP_INTERCEPTORS,\r\n useClass: MedHassoAuthInterceptor,\r\n multi: true\r\n }\r\n ];\r\n }\r\n\r\n /**\r\n * Merge user configuration with sensible defaults\r\n */\r\n private static mergeWithDefaults(config: MedHassoConfig): MedHassoConfig {\r\n const defaultConfig: Partial<MedHassoConfig> = {\r\n tokenConfig: {\r\n storageType: 'localStorage',\r\n idTokenKey: 'idToken',\r\n refreshTokenKey: 'refreshToken',\r\n refreshBeforeExpiryMinutes: 5,\r\n autoRefresh: true,\r\n ...config.tokenConfig\r\n },\r\n interceptorConfig: {\r\n enabled: true,\r\n authHeaderPrefix: 'Bearer',\r\n excludeUrls: [],\r\n includeUrls: [],\r\n ...config.interceptorConfig\r\n },\r\n securityConfig: {\r\n httpsOnly: true,\r\n secureCookies: true,\r\n additionalCspSources: [],\r\n ...config.securityConfig\r\n }\r\n };\r\n\r\n return {\r\n ...config,\r\n ...defaultConfig,\r\n tokenConfig: {\r\n ...defaultConfig.tokenConfig,\r\n ...config.tokenConfig\r\n },\r\n interceptorConfig: {\r\n ...defaultConfig.interceptorConfig,\r\n ...config.interceptorConfig\r\n },\r\n securityConfig: {\r\n ...defaultConfig.securityConfig,\r\n ...config.securityConfig\r\n }\r\n };\r\n }\r\n}","import { Injectable } from '@angular/core';\r\nimport { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, UrlTree } from '@angular/router';\r\nimport { Observable, of } from 'rxjs';\r\nimport { map, catchError } from 'rxjs/operators';\r\nimport { TokenManagementService } from '../services/token-management.service';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class MedHassoAuthGuard implements CanActivate, CanActivateChild {\r\n\r\n constructor(\r\n private tokenService: TokenManagementService,\r\n private router: Router\r\n ) {}\r\n\r\n canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n return this.checkAuthentication(route);\r\n }\r\n\r\n canActivateChild(childRoute: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n return this.checkAuthentication(childRoute);\r\n }\r\n\r\n private checkAuthentication(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> {\r\n // Check for authentication callback parameters\r\n if (this.handleAuthCallback(route)) {\r\n return of(true);\r\n }\r\n\r\n // Re-syncs from storage and refreshes a stale/expired token before\r\n // deciding, so this guard shares the same de-duplicated refresh and\r\n // storage-drift handling as the HTTP interceptor.\r\n return this.tokenService.ensureValidToken().pipe(\r\n map(valid => {\r\n if (!valid) {\r\n this.tokenService.redirectToSSO();\r\n return false;\r\n }\r\n return true;\r\n }),\r\n catchError(() => {\r\n this.tokenService.redirectToSSO();\r\n return of(false);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Handle authentication callback from MedHasso SSO\r\n */\r\n private handleAuthCallback(route: ActivatedRouteSnapshot): boolean {\r\n const queryParams = route.queryParams;\r\n \r\n // Check for AIRO redirect flow\r\n if (queryParams['redirectapp'] === 'airo' && queryParams['idToken']) {\r\n return this.tokenService.handleAuthCallback({\r\n idToken: queryParams['idToken'],\r\n refreshToken: queryParams['refreshToken']\r\n });\r\n }\r\n\r\n // Check for standard authentication callback\r\n if (queryParams['idToken'] || queryParams['token']) {\r\n return this.tokenService.handleAuthCallback({\r\n idToken: queryParams['idToken'] || queryParams['token'],\r\n refreshToken: queryParams['refreshToken']\r\n });\r\n }\r\n\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Role-based authentication guard\r\n */\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class MedHassoRoleGuard implements CanActivate, CanActivateChild {\r\n\r\n constructor(\r\n private tokenService: TokenManagementService,\r\n private router: Router\r\n ) {}\r\n\r\n canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n return this.checkRole(route);\r\n }\r\n\r\n canActivateChild(childRoute: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n return this.checkRole(childRoute);\r\n }\r\n\r\n private checkRole(route: ActivatedRouteSnapshot): boolean | UrlTree {\r\n const requiredRoles = route.data['roles'] as string[];\r\n const requiredRole = route.data['role'] as string;\r\n\r\n if (!this.tokenService.isAuthenticated()) {\r\n this.tokenService.redirectToSSO();\r\n return false;\r\n }\r\n\r\n // Check multiple roles (OR condition)\r\n if (requiredRoles && requiredRoles.length > 0) {\r\n const hasAnyRole = requiredRoles.some(role => this.tokenService.hasRole(role));\r\n if (!hasAnyRole) {\r\n return this.router.createUrlTree(['/unauthorized']);\r\n }\r\n }\r\n\r\n // Check single role\r\n if (requiredRole && !this.tokenService.hasRole(requiredRole)) {\r\n return this.router.createUrlTree(['/unauthorized']);\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n\r\n/**\r\n * Admin-only authentication guard\r\n */\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class MedHassoAdminGuard implements CanActivate, CanActivateChild {\r\n\r\n constructor(\r\n private tokenService: TokenManagementService,\r\n private router: Router\r\n ) {}\r\n\r\n canActivate(): boolean | UrlTree {\r\n return this.checkAdmin();\r\n }\r\n\r\n canActivateChild(): boolean | UrlTree {\r\n return this.checkAdmin();\r\n }\r\n\r\n private checkAdmin(): boolean | UrlTree {\r\n if (!this.tokenService.isAuthenticated()) {\r\n this.tokenService.redirectToSSO();\r\n return false;\r\n }\r\n\r\n if (!this.tokenService.isAdmin()) {\r\n return this.router.createUrlTree(['/unauthorized']);\r\n }\r\n\r\n return true;\r\n }\r\n}","/*\r\n * Public API Surface of medhasso-auth\r\n */\r\n\r\n// Module\r\nexport * from './lib/medhasso-auth.module';\r\n\r\n// Services\r\nexport * from './lib/services/token-management.service';\r\nexport * from './lib/services/medhasso-auth.service';\r\n\r\n// Guards\r\nexport * from './lib/guards/medhasso-auth.guard';\r\n\r\n// Interceptors\r\nexport * from './lib/interceptors/medhasso-auth.interceptor';\r\n\r\n// Interfaces\r\nexport * from './lib/interfaces/medhasso-config.interface';\r\n\r\n// Tokens\r\nexport * from './lib/tokens/medhasso-config.token';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.TokenManagementService","i2"],"mappings":"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"}
|
|
@@ -13,10 +13,6 @@ export declare class MedHassoAuthGuard implements CanActivate, CanActivateChild
|
|
|
13
13
|
* Handle authentication callback from MedHasso SSO
|
|
14
14
|
*/
|
|
15
15
|
private handleAuthCallback;
|
|
16
|
-
/**
|
|
17
|
-
* Refresh token if needed
|
|
18
|
-
*/
|
|
19
|
-
private refreshTokenIfNeeded;
|
|
20
16
|
static ɵfac: i0.ɵɵFactoryDeclaration<MedHassoAuthGuard, never>;
|
|
21
17
|
static ɵprov: i0.ɵɵInjectableDeclaration<MedHassoAuthGuard>;
|
|
22
18
|
}
|
|
@@ -6,8 +6,11 @@ export declare class TokenManagementService {
|
|
|
6
6
|
private config;
|
|
7
7
|
private http;
|
|
8
8
|
private refreshTokenInterval;
|
|
9
|
+
private refreshInProgress$;
|
|
9
10
|
private tokenSubject;
|
|
10
11
|
private userSubject;
|
|
12
|
+
private readonly onVisibilityChange;
|
|
13
|
+
private readonly onWindowFocus;
|
|
11
14
|
token$: Observable<TokenInfo | null>;
|
|
12
15
|
user$: Observable<MedHassoUser | null>;
|
|
13
16
|
private get tokenConfig();
|
|
@@ -17,10 +20,27 @@ export declare class TokenManagementService {
|
|
|
17
20
|
private get refreshBeforeExpiryMinutes();
|
|
18
21
|
private get autoRefresh();
|
|
19
22
|
constructor(config: MedHassoConfig, http: HttpClient);
|
|
23
|
+
/**
|
|
24
|
+
* Re-validate the token whenever the tab regains focus/visibility.
|
|
25
|
+
* The refresh timer is a JS timer and does not fire while the OS/browser
|
|
26
|
+
* was suspended (e.g. laptop sleep overnight), so it can't be relied on
|
|
27
|
+
* alone to catch a token that went stale while the app was inactive.
|
|
28
|
+
*/
|
|
29
|
+
private setupWakeDetection;
|
|
30
|
+
/**
|
|
31
|
+
* Remove wake-detection listeners registered in setupWakeDetection().
|
|
32
|
+
*/
|
|
33
|
+
private teardownWakeDetection;
|
|
20
34
|
/**
|
|
21
35
|
* Initialize token information from storage
|
|
22
36
|
*/
|
|
23
37
|
private initializeFromStorage;
|
|
38
|
+
/**
|
|
39
|
+
* Re-sync in-memory token state from storage if it has drifted (e.g.
|
|
40
|
+
* something wrote tokens directly to storage without going through
|
|
41
|
+
* setTokens()). No-op when storage already matches memory.
|
|
42
|
+
*/
|
|
43
|
+
private syncFromStorage;
|
|
24
44
|
/**
|
|
25
45
|
* Get stored token from configured storage
|
|
26
46
|
*/
|
|
@@ -82,9 +102,37 @@ export declare class TokenManagementService {
|
|
|
82
102
|
*/
|
|
83
103
|
setTokens(idToken: string, refreshToken?: string): void;
|
|
84
104
|
/**
|
|
85
|
-
* Refresh the current token
|
|
105
|
+
* Refresh the current token.
|
|
106
|
+
* Concurrent callers (auto-refresh timer, wake detection, interceptor,
|
|
107
|
+
* route guard) share the same in-flight request instead of each firing
|
|
108
|
+
* their own POST to the refresh endpoint.
|
|
86
109
|
*/
|
|
87
110
|
refreshToken(): Observable<any>;
|
|
111
|
+
/**
|
|
112
|
+
* Ensure the current token is valid, refreshing it first if it is
|
|
113
|
+
* expired. Resolves `false` if there is no token at all, or the token
|
|
114
|
+
* is expired and refreshing it failed (in both cases the caller should
|
|
115
|
+
* redirect to SSO).
|
|
116
|
+
*
|
|
117
|
+
* A token that merely `needsRefresh` (inside the refresh window, but
|
|
118
|
+
* not yet expired) is still good enough to use: the refresh for it is
|
|
119
|
+
* kicked off in the background so the *current* request/route isn't
|
|
120
|
+
* blocked or logged out by a transient refresh failure (network blip,
|
|
121
|
+
* refresh endpoint hiccup) while the existing token would have worked
|
|
122
|
+
* fine. Only an actually-expired token blocks the caller.
|
|
123
|
+
*
|
|
124
|
+
* Re-syncs from storage first: the in-memory token snapshot is only
|
|
125
|
+
* updated via setTokens()/logout(), so if something wrote directly to
|
|
126
|
+
* storage (e.g. the SSO callback flow) without going through this
|
|
127
|
+
* service, the in-memory copy would otherwise be stale until the next
|
|
128
|
+
* full page load re-runs initializeFromStorage().
|
|
129
|
+
*
|
|
130
|
+
* Anonymous/bootstrap endpoints that must be reachable before any token
|
|
131
|
+
* exists (e.g. the SSO callback's own token-exchange request) should be
|
|
132
|
+
* added to `interceptorConfig.excludeUrls` so they bypass this check
|
|
133
|
+
* entirely, rather than relying on this method to let them through.
|
|
134
|
+
*/
|
|
135
|
+
ensureValidToken(): Observable<boolean>;
|
|
88
136
|
/**
|
|
89
137
|
* Logout user and clear all tokens
|
|
90
138
|
*/
|