@medha-analytics/medhasso-auth 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,813 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, Inject, Injectable, NgModule } from '@angular/core';
3
+ import * as i1 from '@angular/common/http';
4
+ import { HTTP_INTERCEPTORS } from '@angular/common/http';
5
+ import { BehaviorSubject, timer, throwError, of } from 'rxjs';
6
+ import { tap, catchError, switchMap, map } from 'rxjs/operators';
7
+ import * as i2 from '@angular/router';
8
+
9
+ const MEDHASSO_CONFIG = new InjectionToken('MEDHASSO_CONFIG');
10
+
11
+ class TokenManagementService {
12
+ get tokenConfig() {
13
+ return this.config.tokenConfig || {};
14
+ }
15
+ get storageType() {
16
+ return this.tokenConfig.storageType || 'localStorage';
17
+ }
18
+ get idTokenKey() {
19
+ return this.tokenConfig.idTokenKey || 'idToken';
20
+ }
21
+ get refreshTokenKey() {
22
+ return this.tokenConfig.refreshTokenKey || 'refreshToken';
23
+ }
24
+ get refreshBeforeExpiryMinutes() {
25
+ return this.tokenConfig.refreshBeforeExpiryMinutes || 5;
26
+ }
27
+ get autoRefresh() {
28
+ return this.tokenConfig.autoRefresh !== false;
29
+ }
30
+ constructor(config, http) {
31
+ this.config = config;
32
+ this.http = http;
33
+ this.tokenSubject = new BehaviorSubject(null);
34
+ this.userSubject = new BehaviorSubject(null);
35
+ this.token$ = this.tokenSubject.asObservable();
36
+ this.user$ = this.userSubject.asObservable();
37
+ this.initializeFromStorage();
38
+ }
39
+ /**
40
+ * Initialize token information from storage
41
+ */
42
+ initializeFromStorage() {
43
+ const token = this.getStoredToken();
44
+ if (token) {
45
+ const tokenInfo = this.createTokenInfo(token);
46
+ this.tokenSubject.next(tokenInfo);
47
+ this.userSubject.next(this.extractUserFromToken(token));
48
+ if (this.autoRefresh && !tokenInfo.isExpired) {
49
+ this.setTokenRefreshInterval(tokenInfo);
50
+ }
51
+ }
52
+ }
53
+ /**
54
+ * Get stored token from configured storage
55
+ */
56
+ getStoredToken() {
57
+ const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;
58
+ return storage.getItem(this.idTokenKey);
59
+ }
60
+ /**
61
+ * Get stored refresh token from configured storage
62
+ */
63
+ getStoredRefreshToken() {
64
+ const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;
65
+ return storage.getItem(this.refreshTokenKey);
66
+ }
67
+ /**
68
+ * Store tokens in configured storage
69
+ */
70
+ storeTokens(idToken, refreshToken) {
71
+ const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;
72
+ storage.setItem(this.idTokenKey, idToken);
73
+ if (refreshToken) {
74
+ storage.setItem(this.refreshTokenKey, refreshToken);
75
+ }
76
+ }
77
+ /**
78
+ * Clear stored tokens
79
+ */
80
+ clearStoredTokens() {
81
+ const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;
82
+ storage.removeItem(this.idTokenKey);
83
+ storage.removeItem(this.refreshTokenKey);
84
+ }
85
+ /**
86
+ * Create token info object from JWT token
87
+ */
88
+ createTokenInfo(token) {
89
+ const payload = this.decodeJwt(token);
90
+ const expiresAt = payload.exp * 1000; // Convert to milliseconds
91
+ const now = Date.now();
92
+ const refreshWindow = this.refreshBeforeExpiryMinutes * 60 * 1000;
93
+ return {
94
+ token,
95
+ payload,
96
+ expiresAt,
97
+ isExpired: now >= expiresAt,
98
+ needsRefresh: now >= (expiresAt - refreshWindow)
99
+ };
100
+ }
101
+ /**
102
+ * Decode JWT token payload
103
+ */
104
+ decodeJwt(token) {
105
+ try {
106
+ const parts = token.split('.');
107
+ if (parts.length !== 3) {
108
+ throw new Error('Invalid JWT token format');
109
+ }
110
+ const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));
111
+ return payload;
112
+ }
113
+ catch (error) {
114
+ console.error('Error decoding JWT token:', error);
115
+ throw new Error('Invalid JWT token');
116
+ }
117
+ }
118
+ /**
119
+ * Extract user information from JWT token
120
+ */
121
+ extractUserFromToken(token) {
122
+ const payload = this.decodeJwt(token);
123
+ return {
124
+ upn: payload.upn || payload.email,
125
+ name: payload.name,
126
+ roles: payload.roles || [],
127
+ ...payload
128
+ };
129
+ }
130
+ /**
131
+ * Set up automatic token refresh interval
132
+ */
133
+ setTokenRefreshInterval(tokenInfo) {
134
+ this.clearTokenRefreshInterval();
135
+ if (!this.autoRefresh || tokenInfo.isExpired) {
136
+ return;
137
+ }
138
+ const remainingTime = tokenInfo.expiresAt - Date.now();
139
+ const refreshTime = remainingTime - (this.refreshBeforeExpiryMinutes * 60 * 1000);
140
+ if (refreshTime > 0) {
141
+ this.refreshTokenInterval = timer(refreshTime).subscribe(() => {
142
+ this.refreshToken().subscribe();
143
+ });
144
+ }
145
+ else {
146
+ // Token needs immediate refresh
147
+ this.refreshToken().subscribe();
148
+ }
149
+ }
150
+ /**
151
+ * Clear token refresh interval
152
+ */
153
+ clearTokenRefreshInterval() {
154
+ if (this.refreshTokenInterval) {
155
+ this.refreshTokenInterval.unsubscribe();
156
+ this.refreshTokenInterval = null;
157
+ }
158
+ }
159
+ /**
160
+ * Get current token information
161
+ */
162
+ getTokenInfo() {
163
+ return this.tokenSubject.value;
164
+ }
165
+ /**
166
+ * Get current user information
167
+ */
168
+ getCurrentUser() {
169
+ return this.userSubject.value;
170
+ }
171
+ /**
172
+ * Check if user is authenticated
173
+ */
174
+ isAuthenticated() {
175
+ const tokenInfo = this.getTokenInfo();
176
+ return tokenInfo !== null && !tokenInfo.isExpired;
177
+ }
178
+ /**
179
+ * Check if user has specific role
180
+ */
181
+ hasRole(role) {
182
+ const user = this.getCurrentUser();
183
+ return user?.roles?.includes(role) || false;
184
+ }
185
+ /**
186
+ * Check if user is admin
187
+ */
188
+ isAdmin() {
189
+ return this.hasRole('admin') || this.hasRole('administrator');
190
+ }
191
+ /**
192
+ * Set tokens (typically called after successful authentication)
193
+ */
194
+ setTokens(idToken, refreshToken) {
195
+ this.storeTokens(idToken, refreshToken);
196
+ const tokenInfo = this.createTokenInfo(idToken);
197
+ const user = this.extractUserFromToken(idToken);
198
+ this.tokenSubject.next(tokenInfo);
199
+ this.userSubject.next(user);
200
+ if (this.autoRefresh) {
201
+ this.setTokenRefreshInterval(tokenInfo);
202
+ }
203
+ }
204
+ /**
205
+ * Refresh the current token
206
+ */
207
+ refreshToken() {
208
+ const refreshToken = this.getStoredRefreshToken();
209
+ if (!refreshToken) {
210
+ return throwError(() => new Error('No refresh token available'));
211
+ }
212
+ return this.http.post(`${this.config.refreshUrl}/api/refresh-token`, { refreshToken })
213
+ .pipe(tap((response) => {
214
+ if (response.id_token) {
215
+ this.setTokens(response.id_token, response.refresh_token);
216
+ }
217
+ }), catchError(error => {
218
+ console.error('Token refresh failed:', error);
219
+ this.logout();
220
+ return throwError(() => error);
221
+ }));
222
+ }
223
+ /**
224
+ * Logout user and clear all tokens
225
+ */
226
+ logout() {
227
+ this.clearTokenRefreshInterval();
228
+ this.clearStoredTokens();
229
+ this.tokenSubject.next(null);
230
+ this.userSubject.next(null);
231
+ }
232
+ /**
233
+ * Redirect to MedHasso SSO for authentication
234
+ */
235
+ redirectToSSO(returnUrl) {
236
+ const currentUrl = returnUrl || window.location.href;
237
+ const ssoUrl = `${this.config.ssoUrl}?url=${encodeURIComponent(currentUrl)}&applicationName=${encodeURIComponent(this.config.applicationName)}`;
238
+ window.location.href = ssoUrl;
239
+ }
240
+ /**
241
+ * Handle authentication callback (typically from SSO redirect)
242
+ */
243
+ handleAuthCallback(params) {
244
+ if (params.idToken) {
245
+ this.setTokens(params.idToken, params.refreshToken);
246
+ return true;
247
+ }
248
+ return false;
249
+ }
250
+ /**
251
+ * Get authorization header value
252
+ */
253
+ getAuthorizationHeader() {
254
+ const tokenInfo = this.getTokenInfo();
255
+ if (tokenInfo && !tokenInfo.isExpired) {
256
+ const prefix = this.config.interceptorConfig?.authHeaderPrefix || 'Bearer';
257
+ return `${prefix} ${tokenInfo.token}`;
258
+ }
259
+ return null;
260
+ }
261
+ /**
262
+ * Cleanup on service destruction
263
+ */
264
+ ngOnDestroy() {
265
+ this.clearTokenRefreshInterval();
266
+ }
267
+ 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
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TokenManagementService, providedIn: 'root' }); }
269
+ }
270
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TokenManagementService, decorators: [{
271
+ type: Injectable,
272
+ args: [{
273
+ providedIn: 'root'
274
+ }]
275
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
276
+ type: Inject,
277
+ args: [MEDHASSO_CONFIG]
278
+ }] }, { type: i1.HttpClient }] });
279
+
280
+ class MedHassoAuthInterceptor {
281
+ constructor(config, tokenService) {
282
+ this.config = config;
283
+ this.tokenService = tokenService;
284
+ }
285
+ intercept(request, next) {
286
+ // Check if interceptor is enabled
287
+ if (this.config.interceptorConfig?.enabled === false) {
288
+ return next.handle(request);
289
+ }
290
+ // Check if request should be excluded
291
+ if (this.shouldExcludeRequest(request)) {
292
+ return next.handle(request);
293
+ }
294
+ // Check if request should be included (if includeUrls is specified)
295
+ if (!this.shouldIncludeRequest(request)) {
296
+ return next.handle(request);
297
+ }
298
+ // Add authorization header
299
+ const modifiedRequest = this.addAuthorizationHeader(request);
300
+ return next.handle(modifiedRequest).pipe(catchError((error) => {
301
+ // Handle 401 Unauthorized errors
302
+ if (error.status === 401) {
303
+ return this.handle401Error(request, next);
304
+ }
305
+ // Handle 403 Forbidden errors
306
+ if (error.status === 403) {
307
+ console.warn('MedHasso Auth: Access forbidden (403)', error);
308
+ }
309
+ return throwError(() => error);
310
+ }));
311
+ }
312
+ /**
313
+ * Check if request URL should be excluded from authentication
314
+ */
315
+ shouldExcludeRequest(request) {
316
+ const excludeUrls = this.config.interceptorConfig?.excludeUrls || [];
317
+ return excludeUrls.some(url => this.matchesUrl(request.url, url));
318
+ }
319
+ /**
320
+ * Check if request URL should be included for authentication
321
+ * If includeUrls is not specified, all requests are included (unless excluded)
322
+ */
323
+ shouldIncludeRequest(request) {
324
+ const includeUrls = this.config.interceptorConfig?.includeUrls;
325
+ // If no includeUrls specified, include all requests
326
+ if (!includeUrls || includeUrls.length === 0) {
327
+ return true;
328
+ }
329
+ // If includeUrls specified, only include matching requests
330
+ return includeUrls.some(url => this.matchesUrl(request.url, url));
331
+ }
332
+ /**
333
+ * Check if request URL matches the pattern
334
+ */
335
+ matchesUrl(requestUrl, pattern) {
336
+ // Support wildcards and exact matches
337
+ if (pattern.includes('*')) {
338
+ const regex = new RegExp(pattern.replace(/\*/g, '.*'));
339
+ return regex.test(requestUrl);
340
+ }
341
+ return requestUrl.includes(pattern);
342
+ }
343
+ /**
344
+ * Add authorization header to request
345
+ */
346
+ addAuthorizationHeader(request) {
347
+ const authHeader = this.tokenService.getAuthorizationHeader();
348
+ if (!authHeader) {
349
+ return request;
350
+ }
351
+ return request.clone({
352
+ setHeaders: {
353
+ Authorization: authHeader
354
+ }
355
+ });
356
+ }
357
+ /**
358
+ * Handle 401 Unauthorized errors by attempting token refresh
359
+ */
360
+ handle401Error(request, next) {
361
+ const tokenInfo = this.tokenService.getTokenInfo();
362
+ // If no token or token is expired, redirect to SSO
363
+ if (!tokenInfo || tokenInfo.isExpired) {
364
+ this.redirectToSSO();
365
+ return throwError(() => new Error('Authentication required'));
366
+ }
367
+ // If token exists but request failed, try to refresh
368
+ return this.tokenService.refreshToken().pipe(switchMap(() => {
369
+ // Retry the original request with new token
370
+ const retryRequest = this.addAuthorizationHeader(request);
371
+ return next.handle(retryRequest);
372
+ }), catchError((refreshError) => {
373
+ // If refresh fails, redirect to SSO
374
+ console.error('MedHasso Auth: Token refresh failed', refreshError);
375
+ this.redirectToSSO();
376
+ return throwError(() => refreshError);
377
+ }));
378
+ }
379
+ /**
380
+ * Redirect to SSO for authentication
381
+ */
382
+ redirectToSSO() {
383
+ // Add a small delay to prevent multiple redirects
384
+ setTimeout(() => {
385
+ this.tokenService.redirectToSSO();
386
+ }, 100);
387
+ }
388
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthInterceptor, deps: [{ token: MEDHASSO_CONFIG }, { token: TokenManagementService }], target: i0.ɵɵFactoryTarget.Injectable }); }
389
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthInterceptor }); }
390
+ }
391
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthInterceptor, decorators: [{
392
+ type: Injectable
393
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
394
+ type: Inject,
395
+ args: [MEDHASSO_CONFIG]
396
+ }] }, { type: TokenManagementService }] });
397
+
398
+ class MedHassoAuthService {
399
+ constructor(config, tokenService, http) {
400
+ this.config = config;
401
+ this.tokenService = tokenService;
402
+ this.http = http;
403
+ }
404
+ /**
405
+ * Get current authentication status
406
+ */
407
+ isAuthenticated() {
408
+ return this.tokenService.isAuthenticated();
409
+ }
410
+ /**
411
+ * Get current user information
412
+ */
413
+ getCurrentUser() {
414
+ return this.tokenService.getCurrentUser();
415
+ }
416
+ /**
417
+ * Get current user as observable
418
+ */
419
+ getCurrentUser$() {
420
+ return this.tokenService.user$;
421
+ }
422
+ /**
423
+ * Check if user has specific role
424
+ */
425
+ hasRole(role) {
426
+ return this.tokenService.hasRole(role);
427
+ }
428
+ /**
429
+ * Check if user has any of the specified roles
430
+ */
431
+ hasAnyRole(roles) {
432
+ return roles.some(role => this.tokenService.hasRole(role));
433
+ }
434
+ /**
435
+ * Check if user has all of the specified roles
436
+ */
437
+ hasAllRoles(roles) {
438
+ return roles.every(role => this.tokenService.hasRole(role));
439
+ }
440
+ /**
441
+ * Check if user is admin
442
+ */
443
+ isAdmin() {
444
+ return this.tokenService.isAdmin();
445
+ }
446
+ /**
447
+ * Login user (redirect to SSO)
448
+ */
449
+ login(returnUrl) {
450
+ this.tokenService.redirectToSSO(returnUrl);
451
+ }
452
+ /**
453
+ * Logout user
454
+ */
455
+ logout() {
456
+ this.tokenService.logout();
457
+ }
458
+ /**
459
+ * Refresh authentication token
460
+ */
461
+ refreshToken() {
462
+ return this.tokenService.refreshToken();
463
+ }
464
+ /**
465
+ * Check access permissions for a simple key (if applicable)
466
+ */
467
+ checkAccess(simpleKey, backendUrl) {
468
+ const url = backendUrl || this.getBackendUrl();
469
+ if (!url) {
470
+ return of(null);
471
+ }
472
+ return this.http.get(`${url}/auth/guard?simple_key=${simpleKey}`)
473
+ .pipe(catchError(error => {
474
+ console.error('Access check failed:', error);
475
+ return of(null);
476
+ }));
477
+ }
478
+ /**
479
+ * Check if user is admin via backend API (if applicable)
480
+ */
481
+ checkIsAdmin(backendUrl) {
482
+ const user = this.getCurrentUser();
483
+ const url = backendUrl || this.getBackendUrl();
484
+ if (!user?.upn || !url) {
485
+ return of(false);
486
+ }
487
+ return this.http.get(`${url}/isAdmin?email=${user.upn}`)
488
+ .pipe(map((response) => !!response), catchError(() => of(false)));
489
+ }
490
+ /**
491
+ * Get backend URL from config (helper method)
492
+ */
493
+ getBackendUrl() {
494
+ // This would need to be configured or passed in
495
+ // For now, return null as it's application-specific
496
+ return null;
497
+ }
498
+ /**
499
+ * Get token information
500
+ */
501
+ getTokenInfo() {
502
+ return this.tokenService.getTokenInfo();
503
+ }
504
+ /**
505
+ * Get token as observable
506
+ */
507
+ getToken$() {
508
+ return this.tokenService.token$;
509
+ }
510
+ /**
511
+ * Handle authentication callback
512
+ */
513
+ handleAuthCallback(params) {
514
+ return this.tokenService.handleAuthCallback(params);
515
+ }
516
+ /**
517
+ * Get user email
518
+ */
519
+ getUserEmail() {
520
+ return this.getCurrentUser()?.upn || null;
521
+ }
522
+ /**
523
+ * Get user display name
524
+ */
525
+ getUserDisplayName() {
526
+ return this.getCurrentUser()?.name || null;
527
+ }
528
+ /**
529
+ * Get all user roles
530
+ */
531
+ getUserRoles() {
532
+ return this.getCurrentUser()?.roles || [];
533
+ }
534
+ /**
535
+ * Get authorization header value
536
+ */
537
+ getAuthorizationHeader() {
538
+ return this.tokenService.getAuthorizationHeader();
539
+ }
540
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthService, deps: [{ token: MEDHASSO_CONFIG }, { token: TokenManagementService }, { token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
541
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthService, providedIn: 'root' }); }
542
+ }
543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthService, decorators: [{
544
+ type: Injectable,
545
+ args: [{
546
+ providedIn: 'root'
547
+ }]
548
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
549
+ type: Inject,
550
+ args: [MEDHASSO_CONFIG]
551
+ }] }, { type: TokenManagementService }, { type: i1.HttpClient }] });
552
+
553
+ class MedHassoAuthModule {
554
+ /**
555
+ * Configure the MedHasso authentication module with required settings
556
+ */
557
+ static forRoot(config) {
558
+ return {
559
+ ngModule: MedHassoAuthModule,
560
+ providers: [
561
+ {
562
+ provide: MEDHASSO_CONFIG,
563
+ useValue: this.mergeWithDefaults(config)
564
+ },
565
+ TokenManagementService,
566
+ MedHassoAuthService,
567
+ {
568
+ provide: HTTP_INTERCEPTORS,
569
+ useClass: MedHassoAuthInterceptor,
570
+ multi: true
571
+ }
572
+ ]
573
+ };
574
+ }
575
+ /**
576
+ * Configure the MedHasso authentication module for feature modules
577
+ */
578
+ static forChild() {
579
+ return {
580
+ ngModule: MedHassoAuthModule,
581
+ providers: []
582
+ };
583
+ }
584
+ /**
585
+ * Provide MedHasso authentication with standalone components
586
+ */
587
+ static forStandalone(config) {
588
+ return [
589
+ {
590
+ provide: MEDHASSO_CONFIG,
591
+ useValue: this.mergeWithDefaults(config)
592
+ },
593
+ TokenManagementService,
594
+ MedHassoAuthService,
595
+ {
596
+ provide: HTTP_INTERCEPTORS,
597
+ useClass: MedHassoAuthInterceptor,
598
+ multi: true
599
+ }
600
+ ];
601
+ }
602
+ /**
603
+ * Merge user configuration with sensible defaults
604
+ */
605
+ static mergeWithDefaults(config) {
606
+ const defaultConfig = {
607
+ tokenConfig: {
608
+ storageType: 'localStorage',
609
+ idTokenKey: 'idToken',
610
+ refreshTokenKey: 'refreshToken',
611
+ refreshBeforeExpiryMinutes: 5,
612
+ autoRefresh: true,
613
+ ...config.tokenConfig
614
+ },
615
+ interceptorConfig: {
616
+ enabled: true,
617
+ authHeaderPrefix: 'Bearer',
618
+ excludeUrls: [],
619
+ includeUrls: [],
620
+ ...config.interceptorConfig
621
+ },
622
+ securityConfig: {
623
+ httpsOnly: true,
624
+ secureCookies: true,
625
+ additionalCspSources: [],
626
+ ...config.securityConfig
627
+ }
628
+ };
629
+ return {
630
+ ...config,
631
+ ...defaultConfig,
632
+ tokenConfig: {
633
+ ...defaultConfig.tokenConfig,
634
+ ...config.tokenConfig
635
+ },
636
+ interceptorConfig: {
637
+ ...defaultConfig.interceptorConfig,
638
+ ...config.interceptorConfig
639
+ },
640
+ securityConfig: {
641
+ ...defaultConfig.securityConfig,
642
+ ...config.securityConfig
643
+ }
644
+ };
645
+ }
646
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
647
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthModule }); }
648
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthModule }); }
649
+ }
650
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthModule, decorators: [{
651
+ type: NgModule,
652
+ args: [{
653
+ declarations: [],
654
+ imports: [],
655
+ exports: []
656
+ }]
657
+ }] });
658
+
659
+ class MedHassoAuthGuard {
660
+ constructor(tokenService, router) {
661
+ this.tokenService = tokenService;
662
+ this.router = router;
663
+ }
664
+ canActivate(route) {
665
+ return this.checkAuthentication(route);
666
+ }
667
+ canActivateChild(childRoute) {
668
+ return this.checkAuthentication(childRoute);
669
+ }
670
+ checkAuthentication(route) {
671
+ // Check for authentication callback parameters
672
+ if (this.handleAuthCallback(route)) {
673
+ return of(true);
674
+ }
675
+ // Check if user is already authenticated
676
+ if (this.tokenService.isAuthenticated()) {
677
+ return this.refreshTokenIfNeeded().pipe(map(() => true), catchError(() => {
678
+ this.tokenService.redirectToSSO();
679
+ return of(false);
680
+ }));
681
+ }
682
+ // Not authenticated, redirect to SSO
683
+ this.tokenService.redirectToSSO();
684
+ return of(false);
685
+ }
686
+ /**
687
+ * Handle authentication callback from MedHasso SSO
688
+ */
689
+ handleAuthCallback(route) {
690
+ const queryParams = route.queryParams;
691
+ // Check for AIRO redirect flow
692
+ if (queryParams['redirectapp'] === 'airo' && queryParams['idToken']) {
693
+ return this.tokenService.handleAuthCallback({
694
+ idToken: queryParams['idToken'],
695
+ refreshToken: queryParams['refreshToken']
696
+ });
697
+ }
698
+ // Check for standard authentication callback
699
+ if (queryParams['idToken'] || queryParams['token']) {
700
+ return this.tokenService.handleAuthCallback({
701
+ idToken: queryParams['idToken'] || queryParams['token'],
702
+ refreshToken: queryParams['refreshToken']
703
+ });
704
+ }
705
+ return false;
706
+ }
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
+ 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
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthGuard, providedIn: 'root' }); }
719
+ }
720
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAuthGuard, decorators: [{
721
+ type: Injectable,
722
+ args: [{
723
+ providedIn: 'root'
724
+ }]
725
+ }], ctorParameters: () => [{ type: TokenManagementService }, { type: i2.Router }] });
726
+ /**
727
+ * Role-based authentication guard
728
+ */
729
+ class MedHassoRoleGuard {
730
+ constructor(tokenService, router) {
731
+ this.tokenService = tokenService;
732
+ this.router = router;
733
+ }
734
+ canActivate(route) {
735
+ return this.checkRole(route);
736
+ }
737
+ canActivateChild(childRoute) {
738
+ return this.checkRole(childRoute);
739
+ }
740
+ checkRole(route) {
741
+ const requiredRoles = route.data['roles'];
742
+ const requiredRole = route.data['role'];
743
+ if (!this.tokenService.isAuthenticated()) {
744
+ this.tokenService.redirectToSSO();
745
+ return false;
746
+ }
747
+ // Check multiple roles (OR condition)
748
+ if (requiredRoles && requiredRoles.length > 0) {
749
+ const hasAnyRole = requiredRoles.some(role => this.tokenService.hasRole(role));
750
+ if (!hasAnyRole) {
751
+ return this.router.createUrlTree(['/unauthorized']);
752
+ }
753
+ }
754
+ // Check single role
755
+ if (requiredRole && !this.tokenService.hasRole(requiredRole)) {
756
+ return this.router.createUrlTree(['/unauthorized']);
757
+ }
758
+ return true;
759
+ }
760
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoRoleGuard, deps: [{ token: TokenManagementService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
761
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoRoleGuard, providedIn: 'root' }); }
762
+ }
763
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoRoleGuard, decorators: [{
764
+ type: Injectable,
765
+ args: [{
766
+ providedIn: 'root'
767
+ }]
768
+ }], ctorParameters: () => [{ type: TokenManagementService }, { type: i2.Router }] });
769
+ /**
770
+ * Admin-only authentication guard
771
+ */
772
+ class MedHassoAdminGuard {
773
+ constructor(tokenService, router) {
774
+ this.tokenService = tokenService;
775
+ this.router = router;
776
+ }
777
+ canActivate() {
778
+ return this.checkAdmin();
779
+ }
780
+ canActivateChild() {
781
+ return this.checkAdmin();
782
+ }
783
+ checkAdmin() {
784
+ if (!this.tokenService.isAuthenticated()) {
785
+ this.tokenService.redirectToSSO();
786
+ return false;
787
+ }
788
+ if (!this.tokenService.isAdmin()) {
789
+ return this.router.createUrlTree(['/unauthorized']);
790
+ }
791
+ return true;
792
+ }
793
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAdminGuard, deps: [{ token: TokenManagementService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
794
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAdminGuard, providedIn: 'root' }); }
795
+ }
796
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MedHassoAdminGuard, decorators: [{
797
+ type: Injectable,
798
+ args: [{
799
+ providedIn: 'root'
800
+ }]
801
+ }], ctorParameters: () => [{ type: TokenManagementService }, { type: i2.Router }] });
802
+
803
+ /*
804
+ * Public API Surface of medhasso-auth
805
+ */
806
+ // Module
807
+
808
+ /**
809
+ * Generated bundle index. Do not edit.
810
+ */
811
+
812
+ export { MEDHASSO_CONFIG, MedHassoAdminGuard, MedHassoAuthGuard, MedHassoAuthInterceptor, MedHassoAuthModule, MedHassoAuthService, MedHassoRoleGuard, TokenManagementService };
813
+ //# sourceMappingURL=medha-analytics-medhasso-auth.mjs.map