• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

damienbod / angular-auth-oidc-client / 8325066261

18 Mar 2024 10:31AM UTC coverage: 92.928% (-4.1%) from 97.057%
8325066261

Pull #1848

github

web-flow
Merge 89af4870e into 6c778a4a2
Pull Request #1848: moving to strict mode

700 of 818 branches covered (85.57%)

Branch coverage included in aggregate %.

228 of 293 new or added lines in 48 files covered. (77.82%)

11 existing lines in 6 files now uncovered.

2559 of 2689 relevant lines covered (95.17%)

8.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.37
/projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.ts
1
import { Injectable } from '@angular/core';
2
import { forkJoin, Observable, of, throwError } from 'rxjs';
3
import { catchError, switchMap } from 'rxjs/operators';
4
import { AuthStateService } from '../auth-state/auth-state.service';
5
import { ConfigurationService } from '../config/config.service';
6
import { OpenIdConfiguration } from '../config/openid-configuration';
7
import { CallbackContext } from '../flows/callback-context';
8
import { FlowsDataService } from '../flows/flows-data.service';
9
import { ResetAuthDataService } from '../flows/reset-auth-data.service';
10
import { RefreshSessionIframeService } from '../iframe/refresh-session-iframe.service';
11
import { LoggerService } from '../logging/logger.service';
12
import { EventTypes } from '../public-events/event-types';
13
import { PublicEventsService } from '../public-events/public-events.service';
14
import { StoragePersistenceService } from '../storage/storage-persistence.service';
15
import { UserService } from '../user-data/user.service';
16
import { FlowHelper } from '../utils/flowHelper/flow-helper.service';
17
import { IntervalService } from './interval.service';
18
import { RefreshSessionRefreshTokenService } from './refresh-session-refresh-token.service';
19

20
@Injectable({ providedIn: 'root' })
21
export class PeriodicallyTokenCheckService {
1✔
22
  constructor(
23
    private readonly resetAuthDataService: ResetAuthDataService,
15✔
24
    private readonly flowHelper: FlowHelper,
15✔
25
    private readonly flowsDataService: FlowsDataService,
15✔
26
    private readonly loggerService: LoggerService,
15✔
27
    private readonly userService: UserService,
15✔
28
    private readonly authStateService: AuthStateService,
15✔
29
    private readonly refreshSessionIframeService: RefreshSessionIframeService,
15✔
30
    private readonly refreshSessionRefreshTokenService: RefreshSessionRefreshTokenService,
15✔
31
    private readonly intervalService: IntervalService,
15✔
32
    private readonly storagePersistenceService: StoragePersistenceService,
15✔
33
    private readonly publicEventsService: PublicEventsService,
15✔
34
    private readonly configurationService: ConfigurationService
15✔
35
  ) {}
36

37
  startTokenValidationPeriodically(
38
    allConfigs: OpenIdConfiguration[],
39
    currentConfig: OpenIdConfiguration
40
  ): void {
41
    const configsWithSilentRenewEnabled =
42
      this.getConfigsWithSilentRenewEnabled(allConfigs);
9✔
43

44
    if (configsWithSilentRenewEnabled.length <= 0) {
7✔
45
      return;
1✔
46
    }
47

48
    if (this.intervalService.isTokenValidationRunning()) {
6✔
49
      return;
1✔
50
    }
51

52
    const refreshTimeInSeconds = this.getSmallestRefreshTimeFromConfigs(
5✔
53
      configsWithSilentRenewEnabled
54
    );
55
    const periodicallyCheck$ = this.intervalService
5✔
56
      .startPeriodicTokenCheck(refreshTimeInSeconds)
57
      .pipe(
58
        switchMap(() => {
59
          const objectWithConfigIdsAndRefreshEvent: {
60
            [id: string]: Observable<boolean | CallbackContext | null>;
61
          } = {};
5✔
62

63
          configsWithSilentRenewEnabled.forEach((config) => {
5✔
64
            const identifier = config.configId as string;
5✔
65
            const refreshEvent = this.getRefreshEvent(config, allConfigs);
5✔
66

67
            objectWithConfigIdsAndRefreshEvent[identifier] = refreshEvent;
5✔
68
          });
69

70
          return forkJoin(objectWithConfigIdsAndRefreshEvent);
5✔
71
        })
72
      );
73

74
    this.intervalService.runTokenValidationRunning = periodicallyCheck$
5✔
75
      .pipe(catchError((error) => throwError(() => new Error(error))))
2✔
76
      .subscribe({
77
        next: (objectWithConfigIds) => {
78
          for (const [configId, _] of Object.entries(objectWithConfigIds)) {
3✔
79
            this.configurationService
3✔
80
              .getOpenIDConfiguration(configId)
81
              .subscribe((config) => {
82
                this.loggerService.logDebug(
3✔
83
                  config,
84
                  'silent renew, periodic check finished!'
85
                );
86

87
                if (
3✔
88
                  this.flowHelper.isCurrentFlowCodeFlowWithRefreshTokens(config)
89
                ) {
90
                  this.flowsDataService.resetSilentRenewRunning(config);
2✔
91
                }
92
              });
93
          }
94
        },
95
        error: (error) => {
96
          this.loggerService.logError(
2✔
97
            currentConfig,
98
            'silent renew failed!',
99
            error
100
          );
101
        },
102
      });
103
  }
104

105
  private getRefreshEvent(
106
    config: OpenIdConfiguration,
107
    allConfigs: OpenIdConfiguration[]
108
  ): Observable<boolean | CallbackContext | null> {
109
    const shouldStartRefreshEvent =
110
      this.shouldStartPeriodicallyCheckForConfig(config);
5✔
111

112
    if (!shouldStartRefreshEvent) {
5!
113
      return of(null);
×
114
    }
115

116
    const refreshEvent$ = this.createRefreshEventForConfig(config, allConfigs);
5✔
117

118
    this.publicEventsService.fireEvent(EventTypes.SilentRenewStarted);
5✔
119

120
    return refreshEvent$.pipe(
5✔
121
      catchError((error) => {
122
        this.loggerService.logError(config, 'silent renew failed!', error);
2✔
123
        this.publicEventsService.fireEvent(EventTypes.SilentRenewFailed, error);
2✔
124
        this.flowsDataService.resetSilentRenewRunning(config);
2✔
125

126
        return throwError(() => new Error(error));
2✔
127
      })
128
    );
129
  }
130

131
  private getSmallestRefreshTimeFromConfigs(
132
    configsWithSilentRenewEnabled: OpenIdConfiguration[]
133
  ): number {
134
    const result = configsWithSilentRenewEnabled.reduce((prev, curr) =>
5✔
NEW
135
      (prev.tokenRefreshInSeconds ?? 0) < (curr.tokenRefreshInSeconds ?? 0)
×
136
        ? prev
137
        : curr
138
    );
139

140
    return result.tokenRefreshInSeconds ?? 0;
5!
141
  }
142

143
  private getConfigsWithSilentRenewEnabled(
144
    allConfigs: OpenIdConfiguration[]
145
  ): OpenIdConfiguration[] {
146
    return allConfigs.filter((x) => x.silentRenew);
8✔
147
  }
148

149
  private createRefreshEventForConfig(
150
    configuration: OpenIdConfiguration,
151
    allConfigs: OpenIdConfiguration[]
152
  ): Observable<boolean | CallbackContext | null> {
153
    this.loggerService.logDebug(configuration, 'starting silent renew...');
5✔
154

155
    return this.configurationService
5✔
156
      .getOpenIDConfiguration(configuration.configId)
157
      .pipe(
158
        switchMap((config) => {
159
          if (!config?.silentRenew) {
5✔
160
            this.resetAuthDataService.resetAuthorizationData(
1✔
161
              config,
162
              allConfigs
163
            );
164

165
            return of(null);
1✔
166
          }
167

168
          this.flowsDataService.setSilentRenewRunning(config);
4✔
169

170
          if (this.flowHelper.isCurrentFlowCodeFlowWithRefreshTokens(config)) {
4✔
171
            // Retrieve Dynamically Set Custom Params for refresh body
172
            const customParamsRefresh: {
173
              [key: string]: string | number | boolean;
174
            } =
175
              this.storagePersistenceService.read(
4✔
176
                'storageCustomParamsRefresh',
177
                config
178
              ) || {};
179

180
            const { customParamsRefreshTokenRequest } = config;
4✔
181

182
            const mergedParams = {
4✔
183
              ...customParamsRefreshTokenRequest,
184
              ...customParamsRefresh,
185
            };
186

187
            // Refresh Session using Refresh tokens
188
            return this.refreshSessionRefreshTokenService.refreshSessionWithRefreshTokens(
4✔
189
              config,
190
              allConfigs,
191
              mergedParams
192
            );
193
          }
194

195
          // Retrieve Dynamically Set Custom Params
196
          const customParams: { [key: string]: string | number | boolean } =
197
            this.storagePersistenceService.read(
×
198
              'storageCustomParamsAuthRequest',
199
              config
200
            );
201

202
          return this.refreshSessionIframeService.refreshSessionWithIframe(
×
203
            config,
204
            allConfigs,
205
            customParams
206
          );
207
        })
208
      );
209
  }
210

211
  private shouldStartPeriodicallyCheckForConfig(
212
    config: OpenIdConfiguration
213
  ): boolean {
214
    const idToken = this.authStateService.getIdToken(config);
7✔
215
    const isSilentRenewRunning =
216
      this.flowsDataService.isSilentRenewRunning(config);
7✔
217
    const isCodeFlowInProgress =
218
      this.flowsDataService.isCodeFlowInProgress(config);
7✔
219
    const userDataFromStore = this.userService.getUserDataFromStore(config);
7✔
220

221
    this.loggerService.logDebug(
7✔
222
      config,
223
      `Checking: silentRenewRunning: ${isSilentRenewRunning}, isCodeFlowInProgress: ${isCodeFlowInProgress} - has idToken: ${!!idToken} - has userData: ${!!userDataFromStore}`
224
    );
225

226
    const shouldBeExecuted =
227
      !!userDataFromStore &&
7✔
228
      !isSilentRenewRunning &&
229
      !!idToken &&
230
      !isCodeFlowInProgress;
231

232
    if (!shouldBeExecuted) {
7✔
233
      return false;
4✔
234
    }
235

236
    const idTokenExpired =
237
      this.authStateService.hasIdTokenExpiredAndRenewCheckIsEnabled(config);
3✔
238
    const accessTokenExpired =
239
      this.authStateService.hasAccessTokenExpiredIfExpiryExists(config);
3✔
240

241
    return idTokenExpired || accessTokenExpired;
3✔
242
  }
243
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc