@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, switchMap, map } from 'rxjs/operators';
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
- return this.http.post(`${this.config.refreshUrl}/api/refresh-token`, { refreshToken })
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
- // 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);
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
- // Handle 403 Forbidden errors
306
- if (error.status === 403) {
307
- console.warn('MedHasso Auth: Access forbidden (403)', error);
308
- }
309
- return throwError(() => error);
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
- // Check if user is already authenticated
676
- if (this.tokenService.isAuthenticated()) {
677
- return this.refreshTokenIfNeeded().pipe(map(() => true), catchError(() => {
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 of(false);
680
- }));
681
- }
682
- // Not authenticated, redirect to SSO
683
- this.tokenService.redirectToSSO();
684
- return of(false);
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
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medha-analytics/medhasso-auth",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Angular authentication library for MedHasso SSO integration",
5
5
  "keywords": [
6
6
  "angular",