ngx-oauth 3.0.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,13 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injectable, Inject, EventEmitter, Component, ViewEncapsulation, Input, Output, ContentChild, HostListener, PLATFORM_ID, Optional, NgModule } from '@angular/core';
3
- import * as i1 from '@angular/common/http';
4
- import { HttpHeaders, HttpParams, HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
5
- import { filter, map, switchMap, shareReplay, tap, catchError, concatMap, delay } from 'rxjs/operators';
6
- import { ReplaySubject, of, EMPTY, from, noop, firstValueFrom, throwError, Subscription, take } from 'rxjs';
2
+ import { InjectionToken, inject, Injectable, Inject, Component, ViewEncapsulation, Input, Output, ContentChild, HostListener, PLATFORM_ID, Optional, NgModule } from '@angular/core';
3
+ import * as i3 from '@angular/common/http';
4
+ import { HttpHeaders, HttpParams, HttpClient, HttpBackend, HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
5
+ import { shareReplay, map, catchError, filter, switchMap as switchMap$1, tap, concatMap, delay } from 'rxjs/operators';
6
+ import { BehaviorSubject, distinctUntilChanged, switchMap, of, ReplaySubject, from, noop, firstValueFrom, throwError, take, Subscription } from 'rxjs';
7
+ import { __classPrivateFieldGet, __classPrivateFieldSet } from 'tslib';
7
8
  import * as i2 from '@angular/common';
8
9
  import { isPlatformBrowser, CommonModule } from '@angular/common';
9
- import * as i3 from '@angular/forms';
10
+ import * as i3$1 from '@angular/forms';
10
11
  import { FormsModule } from '@angular/forms';
11
12
  import { RouterModule } from '@angular/router';
12
13
 
@@ -16,11 +17,13 @@ const LOCATION = new InjectionToken('Location');
16
17
  const STORAGE = new InjectionToken('Storage');
17
18
  const OAUTH_CONFIG = new InjectionToken('OAuthConfig');
18
19
  const OAUTH_TOKEN = new InjectionToken('OAuthToken');
20
+ const HEADER_APPLICATION = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });
21
+ const OAUTH_HTTP_CLIENT = new InjectionToken('OAuthHttpClient');
19
22
  class OAuthConfig {
20
23
  }
21
- OAuthConfig.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
22
- OAuthConfig.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthConfig, providedIn: 'root', useFactory: () => inject(OAUTH_CONFIG).reduce((p, c) => ({ ...p, ...c }), {}) });
23
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthConfig, decorators: [{
24
+ OAuthConfig.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
25
+ OAuthConfig.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthConfig, providedIn: 'root', useFactory: () => inject(OAUTH_CONFIG).reduce((p, c) => ({ ...p, ...c }), {}) });
26
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthConfig, decorators: [{
24
27
  type: Injectable,
25
28
  args: [{
26
29
  providedIn: 'root',
@@ -52,6 +55,80 @@ var OAuthStatus;
52
55
  OAuthStatus["DENIED"] = "DENIED";
53
56
  })(OAuthStatus || (OAuthStatus = {}));
54
57
 
58
+ var _TokenService_token$;
59
+ const isExpiredToken = (token) => token && token.expires && Date.now() > token.expires || false;
60
+ class TokenService {
61
+ constructor(authConfig, http, zone) {
62
+ this.authConfig = authConfig;
63
+ this.http = http;
64
+ this.zone = zone;
65
+ _TokenService_token$.set(this, new BehaviorSubject(this.saved));
66
+ this.token$ = __classPrivateFieldGet(this, _TokenService_token$, "f").pipe(distinctUntilChanged((p, c) => JSON.stringify(p || null) === JSON.stringify(c || null)), switchMap(token => !isExpiredToken(token) && of(token) || this.refreshToken(token)), shareReplay(1));
67
+ this.type$ = this.token$.pipe(map(token => token?.type), shareReplay(1));
68
+ this.accessToken$ = this.token$.pipe(map(token => token?.access_token), shareReplay(1));
69
+ }
70
+ get token() {
71
+ return __classPrivateFieldGet(this, _TokenService_token$, "f").value;
72
+ }
73
+ set token(token) {
74
+ const expiresIn = Number(token.expires_in) || 0;
75
+ const result = {
76
+ ...token,
77
+ ...expiresIn && { expires: Date.now() + expiresIn * 1000 } || {}
78
+ };
79
+ this.saved = result;
80
+ __classPrivateFieldGet(this, _TokenService_token$, "f").next(result);
81
+ }
82
+ get saved() {
83
+ const { storageKey, storage } = this.authConfig;
84
+ return storageKey && storage && storage[storageKey] && JSON.parse(storage[storageKey]) || {};
85
+ }
86
+ set saved(token) {
87
+ const { storageKey, storage } = this.authConfig;
88
+ if (storage && storageKey) {
89
+ if (token) {
90
+ storage[storageKey] = JSON.stringify(token);
91
+ }
92
+ else {
93
+ delete storage[storageKey];
94
+ }
95
+ }
96
+ }
97
+ refreshToken(token) {
98
+ const { tokenPath, clientId, clientSecret, scope } = this.authConfig.config;
99
+ const { refresh_token } = token || {};
100
+ return tokenPath && refresh_token && this.http.post(tokenPath, new HttpParams({
101
+ fromObject: {
102
+ client_id: clientId,
103
+ ...clientSecret && { client_secret: clientSecret } || {},
104
+ grant_type: 'refresh_token',
105
+ refresh_token,
106
+ ...scope && { scope } || {},
107
+ }
108
+ }), {
109
+ headers: HEADER_APPLICATION
110
+ }).pipe(catchError(() => {
111
+ this.token = {};
112
+ return of(this.token);
113
+ }), map(token => {
114
+ this.token = {
115
+ ...this.token,
116
+ ...token
117
+ };
118
+ return this.token;
119
+ })) || of(token);
120
+ }
121
+ }
122
+ _TokenService_token$ = new WeakMap();
123
+ TokenService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: TokenService, deps: [{ token: OAuthConfig }, { token: OAUTH_HTTP_CLIENT }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
124
+ TokenService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: TokenService });
125
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: TokenService, decorators: [{
126
+ type: Injectable
127
+ }], ctorParameters: function () { return [{ type: OAuthConfig }, { type: i3.HttpClient, decorators: [{
128
+ type: Inject,
129
+ args: [OAUTH_HTTP_CLIENT]
130
+ }] }, { type: i0.NgZone }]; } });
131
+
55
132
  const arrToString = (buf) => buf.reduce((s, b) => s + String.fromCharCode(b), '');
56
133
  const base64url = (str) => btoa(str)
57
134
  .replace(/\+/g, '-')
@@ -65,7 +142,6 @@ const pkce = async (value) => {
65
142
  const buff = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value));
66
143
  return base64url(arrToString(new Uint8Array(buff)));
67
144
  };
68
- const REQUEST_HEADER = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });
69
145
  const parseOauthUri = (hash) => {
70
146
  const regex = /([^&=]+)=([^&]*)/g;
71
147
  const params = {};
@@ -74,81 +150,48 @@ const parseOauthUri = (hash) => {
74
150
  while ((m = regex.exec(hash)) !== null) {
75
151
  params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
76
152
  }
77
- if (Object.keys(params).length) {
78
- return params;
79
- }
80
- return null;
153
+ return Object.keys(params).length && params || {};
81
154
  };
82
155
  const jwt = (token) => JSON.parse(atob(token.split('.')[1]));
83
156
  class OAuthService {
84
- constructor(http, zone, authConfig, location, locationService) {
85
- this.http = http;
86
- this.zone = zone;
157
+ constructor(authConfig, tokenService, http, location, locationService) {
87
158
  this.authConfig = authConfig;
159
+ this.tokenService = tokenService;
160
+ this.http = http;
88
161
  this.location = location;
89
162
  this.locationService = locationService;
90
- this._token = null;
91
- this._status = OAuthStatus.NOT_AUTHORIZED;
92
163
  this.state$ = new ReplaySubject(1);
93
- this.status$ = new ReplaySubject(1);
94
- this.userInfo$ = this.status$.pipe(filter(s => s === OAuthStatus.AUTHORIZED), map(() => {
95
- const { config } = this.authConfig;
96
- return config.userPath;
97
- }), filter(p => !!p), switchMap(path => this.http.get(path)), shareReplay());
98
- setTimeout(() => this.init()); // decouple for http interceptor
99
- }
100
- /**
101
- * Get the oauth config for initialize. If OpenId with issuerPath is configured then configure from server openid configuration.
102
- * @protected
103
- */
104
- get config$() {
105
- let { config } = this.authConfig;
106
- if (config && config.clientId) {
107
- const { issuerPath, scope } = config;
108
- if (issuerPath) {
109
- return this.http.get(`${issuerPath}/.well-known/openid-configuration`).pipe(tap(v => this.type && this.set(this.type, {
110
- ...v.authorization_endpoint && { authorizePath: v.authorization_endpoint } || {},
111
- ...v.token_endpoint && { tokenPath: v.token_endpoint } || {},
112
- ...v.revocation_endpoint && { revokePath: v.revocation_endpoint } || {},
113
- ...v.code_challenge_methods_supported && { pkce: v.code_challenge_methods_supported.indexOf('S256') > -1 } || {},
114
- ...v.userinfo_endpoint && { userPath: v.userinfo_endpoint } || {},
115
- ...v.introspection_endpoint && { introspectionPath: v.introspection_endpoint } || {},
116
- ...v.end_session_endpoint && { logoutPath: v.end_session_endpoint } || {},
117
- ...scope && {} || { scope: 'openid' }
118
- })), map(() => this.authConfig.config));
119
- }
120
- return of(config);
121
- }
122
- console.warn('clientId is missing in oauth config');
123
- return EMPTY;
124
- }
125
- /**
126
- * Init. Will check the url implicit or authorization flow or existing saved token.
127
- * @protected
128
- */
129
- init() {
130
- const { hash, search, origin, pathname } = this.location;
131
- const isImplicitRedirect = hash && /(access_token=)|(error=)/.test(hash);
132
- const isAuthCodeRedirect = search && /(code=)|(error=)/.test(search);
133
- const { storageKey } = this.authConfig;
134
- const savedToken = storageKey && this.authConfig.storage && this.authConfig.storage[storageKey] &&
135
- JSON.parse(this.authConfig.storage[storageKey]);
136
- this.config$.subscribe(config => {
164
+ this.config$ = of(this.config).pipe(filter(Boolean), filter(config => !!config?.clientId), map(config => config), switchMap$1(config => !config.issuerPath && of(config) || this.http.get(`${config.issuerPath}/.well-known/openid-configuration`).pipe(tap(v => this.config = {
165
+ ...v.authorization_endpoint && { authorizePath: v.authorization_endpoint } || {},
166
+ ...v.token_endpoint && { tokenPath: v.token_endpoint } || {},
167
+ ...v.revocation_endpoint && { revokePath: v.revocation_endpoint } || {},
168
+ ...v.code_challenge_methods_supported && { pkce: v.code_challenge_methods_supported.indexOf('S256') > -1 } || {},
169
+ ...v.userinfo_endpoint && { userPath: v.userinfo_endpoint } || {},
170
+ ...v.introspection_endpoint && { introspectionPath: v.introspection_endpoint } || {},
171
+ ...v.end_session_endpoint && { logoutPath: v.end_session_endpoint } || {},
172
+ ...{ scope: config.scope || 'openid' }
173
+ }), map(() => this.config))), shareReplay(1));
174
+ this.token$ = this.config$.pipe(tap(config => {
175
+ const { hash, search, origin, pathname } = this.location;
176
+ const isImplicitRedirect = hash && /(access_token=)|(error=)/.test(hash);
177
+ const isAuthCodeRedirect = search && /(code=)|(error=)/.test(search) || hash && /(code=)|(error=)/.test(hash);
137
178
  if (isImplicitRedirect) {
138
- const parameters = parseOauthUri(hash.substr(1));
139
- this.token = parameters;
140
- this.status = this.checkResponse(savedToken, parameters) && OAuthStatus.AUTHORIZED || OAuthStatus.DENIED;
179
+ const parameters = parseOauthUri(hash.substring(1));
180
+ this.token = {
181
+ ...parameters,
182
+ type: OAuthType.IMPLICIT,
183
+ };
184
+ this.checkResponse(this.token, parameters);
141
185
  }
142
186
  else if (isAuthCodeRedirect) {
143
- const parameters = parseOauthUri(search.substr(1));
144
- if (!this.checkResponse(savedToken, parameters)) {
187
+ const parameters = parseOauthUri(search && search.substring(1) || hash && hash.substring(1));
188
+ if (!this.checkResponse(this.token, parameters)) {
145
189
  this.token = parameters;
146
- this.status = OAuthStatus.DENIED;
147
190
  }
148
191
  else {
149
192
  const newParametersString = this.getCleanedUnSearchParameters();
150
193
  const { clientId, clientSecret, tokenPath, scope } = config;
151
- const codeVerifier = savedToken && savedToken.codeVerifier;
194
+ const { codeVerifier } = this.token || {}; //should be set by authorizationUrl construction
152
195
  this.http.post(tokenPath, new HttpParams({
153
196
  fromObject: {
154
197
  code: parameters?.['code'],
@@ -159,56 +202,55 @@ class OAuthService {
159
202
  ...scope && { scope } || {},
160
203
  ...codeVerifier && { code_verifier: codeVerifier } || {}
161
204
  }
162
- }), { headers: REQUEST_HEADER }).pipe(catchError((err) => {
163
- this.token = err;
164
- this.status = OAuthStatus.DENIED;
165
- this.locationService.replaceState(`${pathname}${newParametersString}`);
166
- return EMPTY;
167
- })).subscribe(token => {
168
- this.token = token;
169
- this.status = OAuthStatus.AUTHORIZED;
205
+ }), { headers: HEADER_APPLICATION }).pipe().subscribe(token => {
206
+ this.token = {
207
+ ...token,
208
+ type: OAuthType.AUTHORIZATION_CODE
209
+ };
170
210
  this.locationService.replaceState(`${pathname}${newParametersString}`);
171
211
  });
172
212
  }
173
213
  }
174
- else if (savedToken) {
175
- this._token = savedToken;
176
- const { access_token, refresh_token, error } = savedToken;
177
- if (access_token) {
178
- if (refresh_token) { // force refresh since might be a manual page refresh
179
- this.refreshToken();
180
- }
181
- else {
182
- this.status = OAuthStatus.AUTHORIZED;
183
- }
184
- }
185
- else {
186
- this.status = error && OAuthStatus.DENIED || OAuthStatus.NOT_AUTHORIZED;
187
- }
188
- }
189
- else {
190
- this.status = OAuthStatus.NOT_AUTHORIZED;
191
- }
192
- });
214
+ }), switchMap$1(() => this.tokenService.token$), shareReplay(1));
215
+ this.status$ = this.token$.pipe(map(token => token.access_token && OAuthStatus.AUTHORIZED || token.error && OAuthStatus.DENIED || OAuthStatus.NOT_AUTHORIZED), shareReplay(1));
216
+ this.userInfo$ = this.status$.pipe(filter(s => s === OAuthStatus.AUTHORIZED), map(() => {
217
+ const { config } = this.authConfig;
218
+ return config.userPath;
219
+ }), filter(Boolean), switchMap$1(path => this.http.get(path)), shareReplay(1));
220
+ this.type$ = this.tokenService.type$;
221
+ this.ignorePaths = this.authConfig.ignorePaths || [];
222
+ }
223
+ get token() {
224
+ return this.tokenService.token;
225
+ }
226
+ set token(token) {
227
+ this.tokenService.token = token;
228
+ }
229
+ get config() {
230
+ return this.authConfig.config;
231
+ }
232
+ set config(config) {
233
+ if (config) {
234
+ this.authConfig.config = {
235
+ ...this.authConfig.config,
236
+ ...config
237
+ };
238
+ }
193
239
  }
194
240
  async login(parameters) {
195
- if (this.isResourceType(parameters)) {
241
+ if (!!parameters && parameters.password) {
196
242
  await this.resourceLogin(parameters);
197
243
  }
198
- else if (this.isAuthorizationCodeType(parameters)) {
199
- await this.authorizationCodeLogin(parameters);
200
- }
201
- else if (this.isImplicitType(parameters)) {
202
- await this.implicitLogin(parameters);
244
+ else if (!!parameters && parameters.redirectUri && parameters.responseType) {
245
+ await this.toAuthorizationUrl(parameters);
203
246
  }
204
- else if (this.isClientCredentialType()) {
247
+ else {
205
248
  await this.clientCredentialLogin();
206
249
  }
207
250
  }
208
251
  logout(useLogoutUrl) {
209
252
  this.revoke();
210
- this.token = null;
211
- this.status = OAuthStatus.NOT_AUTHORIZED;
253
+ this.token = {};
212
254
  const { logoutPath, logoutRedirectUri } = this.authConfig.config;
213
255
  if (useLogoutUrl && logoutPath) {
214
256
  const { origin, pathname } = this.location;
@@ -219,7 +261,7 @@ class OAuthService {
219
261
  revoke() {
220
262
  const { revokePath, clientId, clientSecret } = this.authConfig.config;
221
263
  if (revokePath) {
222
- const { access_token, refresh_token } = this.token;
264
+ const { access_token, refresh_token } = this.token || {};
223
265
  const toRevoke = [];
224
266
  if (access_token) {
225
267
  toRevoke.push({
@@ -238,53 +280,32 @@ class OAuthService {
238
280
  });
239
281
  }
240
282
  from(toRevoke).pipe(concatMap(o => of(o).pipe(delay(300))), // space request to avoid cancellation
241
- switchMap(o => this.http.post(revokePath, new HttpParams({ fromObject: o })))).subscribe(noop);
283
+ switchMap$1(o => this.http.post(revokePath, new HttpParams({ fromObject: o })))).subscribe(noop);
242
284
  }
243
285
  }
244
- get status() {
245
- return this._status;
246
- }
247
- set status(status) {
248
- this._status = status;
249
- this.status$.next(status);
250
- }
251
- set(type, config) {
252
- this.authConfig.type = type;
253
- if (config) {
254
- this.authConfig.config = {
255
- ...this.authConfig.config,
256
- ...config
257
- };
258
- }
259
- }
260
- get type() {
261
- return this.authConfig.type;
262
- }
263
- get ignorePaths() {
264
- return this.authConfig.ignorePaths || [];
265
- }
266
- async clientCredentialLogin() {
286
+ clientCredentialLogin() {
267
287
  const { clientId, clientSecret, tokenPath, scope } = this.authConfig.config;
268
- await firstValueFrom(this.http.post(tokenPath, new HttpParams({
288
+ return firstValueFrom(this.http.post(tokenPath, new HttpParams({
269
289
  fromObject: {
270
290
  client_id: clientId,
271
291
  client_secret: clientSecret,
272
292
  grant_type: OAuthType.CLIENT_CREDENTIAL,
273
293
  ...scope ? { scope } : {},
274
294
  }
275
- }), { headers: REQUEST_HEADER }).pipe(catchError((err) => {
295
+ }), { headers: HEADER_APPLICATION }).pipe(catchError((err) => {
276
296
  this.token = err;
277
- this.status = OAuthStatus.DENIED;
278
- return EMPTY;
297
+ return throwError(() => err);
279
298
  }), tap(params => {
280
- this.token = params;
281
- this.status = OAuthStatus.AUTHORIZED;
299
+ this.token = {
300
+ ...params,
301
+ type: OAuthType.CLIENT_CREDENTIAL,
302
+ };
282
303
  })));
283
304
  }
284
- async resourceLogin(parameters) {
305
+ resourceLogin(parameters) {
285
306
  const { clientId, clientSecret, tokenPath, scope } = this.authConfig.config;
286
307
  const { username, password } = parameters;
287
- await firstValueFrom(this.http.post(tokenPath, new HttpParams({
308
+ return firstValueFrom(this.http.post(tokenPath, new HttpParams({
288
309
  fromObject: {
289
310
  client_id: clientId,
290
311
  ...clientSecret && { client_secret: clientSecret } || {},
@@ -293,45 +314,26 @@ class OAuthService {
293
314
  username,
294
315
  password
295
316
  }
296
- }), { headers: REQUEST_HEADER }).pipe(catchError(err => {
317
+ }), { headers: HEADER_APPLICATION }).pipe(catchError(err => {
297
318
  this.token = err;
298
- this.status = OAuthStatus.DENIED;
299
- return EMPTY;
319
+ return throwError(() => err);
300
320
  }), tap(params => {
301
- this.token = params;
302
- this.status = OAuthStatus.AUTHORIZED;
321
+ this.token = {
322
+ ...params,
323
+ type: OAuthType.RESOURCE,
324
+ };
303
325
  })));
304
326
  }
305
- async implicitLogin(parameters) {
306
- const authUrl = await this.toAuthorizationUrl(parameters, OAuthType.IMPLICIT);
307
- this.location.replace(authUrl);
308
- }
309
- async authorizationCodeLogin(parameters) {
310
- const authUrl = await this.toAuthorizationUrl(parameters, OAuthType.AUTHORIZATION_CODE);
311
- this.location.replace(authUrl);
312
- }
313
- isClientCredentialType() {
314
- return this.authConfig.type === OAuthType.CLIENT_CREDENTIAL;
315
- }
316
- isResourceType(parameters) {
317
- return this.authConfig.type === OAuthType.RESOURCE && !!parameters?.password;
318
- }
319
- isImplicitType(parameters) {
320
- return this.authConfig.type === OAuthType.IMPLICIT && !!parameters?.redirectUri;
321
- }
322
- isAuthorizationCodeType(parameters) {
323
- return this.authConfig.type === OAuthType.AUTHORIZATION_CODE && !!parameters?.redirectUri;
324
- }
325
- async toAuthorizationUrl(parameters, responseType) {
327
+ async toAuthorizationUrl(parameters) {
326
328
  const { config } = this.authConfig;
327
329
  let authorizationUrl = `${config.authorizePath}`;
328
330
  authorizationUrl += config.authorizePath.includes('?') && '&' || '?';
329
331
  authorizationUrl += `client_id=${config.clientId}`;
330
332
  authorizationUrl += `&redirect_uri=${encodeURIComponent(parameters.redirectUri)}`;
331
- authorizationUrl += `&response_type=${responseType}`;
333
+ authorizationUrl += `&response_type=${parameters.responseType}`;
332
334
  authorizationUrl += `&scope=${encodeURIComponent(config.scope || '')}`;
333
335
  authorizationUrl += `&state=${encodeURIComponent(parameters.state || '')}`;
334
- return `${authorizationUrl}${this.generateNonce(config)}${await this.generateCodeChallenge(config)}`;
336
+ return this.location.replace(`${authorizationUrl}${this.generateNonce(config)}${await this.generateCodeChallenge(config)}`);
335
337
  }
336
338
  async generateCodeChallenge(config) {
337
339
  if (config.pkce) {
@@ -361,60 +363,11 @@ class OAuthService {
361
363
  }
362
364
  return parameters['access_token'] || parameters['code'];
363
365
  }
364
- set token(token) {
365
- this._token = token;
366
- const { storageKey } = this.authConfig;
367
- if (token) {
368
- // @ts-ignore
369
- this.authConfig.storage[storageKey] = JSON.stringify(this.token);
370
- clearTimeout(this.timer);
371
- if (this.token && this.token.expires_in) {
372
- this.zone.runOutsideAngular(() => {
373
- this.timer = setTimeout(() => {
374
- this.zone.run(() => {
375
- this.refreshToken();
376
- });
377
- }, Number(this.token?.expires_in) * 1000);
378
- });
379
- }
380
- }
381
- else {
382
- // @ts-ignore
383
- delete this.authConfig.storage[storageKey];
384
- }
385
- }
386
- get token() {
387
- return this._token;
388
- }
389
- refreshToken() {
390
- const { tokenPath, clientId, clientSecret, scope } = this.authConfig.config;
391
- const { refresh_token } = this.token;
392
- if (tokenPath && refresh_token) {
393
- this.http.post(tokenPath, new HttpParams({
394
- fromObject: {
395
- client_id: clientId,
396
- ...clientSecret && { client_secret: clientSecret } || {},
397
- grant_type: 'refresh_token',
398
- refresh_token,
399
- ...scope && { scope } || {},
400
- }
401
- }), { headers: REQUEST_HEADER }).pipe(catchError(() => {
402
- this.logout();
403
- return EMPTY;
404
- })).subscribe(params => {
405
- this.token = {
406
- ...this.token,
407
- ...params
408
- };
409
- this.status = OAuthStatus.AUTHORIZED;
410
- });
411
- }
412
- }
413
366
  getCleanedUnSearchParameters() {
414
367
  const { search } = this.location;
415
- let searchString = search.substr(1);
368
+ let searchString = search && search.substring(1) || '';
416
369
  const hashKeys = ['code', 'state', 'error', 'error_description', 'session_state', 'scope', 'authuser', 'prompt'];
417
- hashKeys.forEach((hashKey) => {
370
+ hashKeys.forEach(hashKey => {
418
371
  const re = new RegExp('&' + hashKey + '(=[^&]*)?|^' + hashKey + '(=[^&]*)?&?');
419
372
  searchString = searchString.replace(re, '');
420
373
  });
@@ -422,62 +375,69 @@ class OAuthService {
422
375
  }
423
376
  cleanLocationHash() {
424
377
  const { hash } = this.location;
425
- let curHash = hash.substr(1);
426
- const hashKeys = ['access_token', 'token_type', 'expires_in', 'scope', 'state', 'error', 'error_description', 'session_state', 'nonce'];
427
- hashKeys.forEach((hashKey) => {
378
+ let curHash = hash && hash.substring(1) || '';
379
+ const hashKeys = [
380
+ 'access_token',
381
+ 'token_type',
382
+ 'expires_in',
383
+ 'scope',
384
+ 'state',
385
+ 'error',
386
+ 'error_description',
387
+ 'session_state',
388
+ 'nonce',
389
+ 'id_token',
390
+ 'code'
391
+ ];
392
+ hashKeys.forEach(hashKey => {
428
393
  const re = new RegExp('&' + hashKey + '(=[^&]*)?|^' + hashKey + '(=[^&]*)?&?');
429
394
  curHash = curHash.replace(re, '');
430
395
  });
431
396
  this.location.hash = curHash;
432
397
  }
433
398
  emitState(parameters) {
434
- const { state } = parameters;
435
- if (state) {
436
- this.state$.next(state);
437
- }
399
+ const { state } = parameters || {};
400
+ state && this.state$.next(state);
438
401
  }
439
402
  }
440
- OAuthService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthService, deps: [{ token: i1.HttpClient }, { token: i0.NgZone }, { token: OAuthConfig }, { token: LOCATION }, { token: i2.Location }], target: i0.ɵɵFactoryTarget.Injectable });
441
- OAuthService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthService });
442
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthService, decorators: [{
403
+ OAuthService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthService, deps: [{ token: OAuthConfig }, { token: TokenService }, { token: i3.HttpClient }, { token: LOCATION }, { token: i2.Location }], target: i0.ɵɵFactoryTarget.Injectable });
404
+ OAuthService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthService });
405
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthService, decorators: [{
443
406
  type: Injectable
444
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i0.NgZone }, { type: OAuthConfig }, { type: Location, decorators: [{
407
+ }], ctorParameters: function () { return [{ type: OAuthConfig }, { type: TokenService }, { type: i3.HttpClient }, { type: Location, decorators: [{
445
408
  type: Inject,
446
409
  args: [LOCATION]
447
410
  }] }, { type: i2.Location }]; } });
448
411
 
449
412
  class OAuthInterceptor {
450
- constructor(oauthService) {
451
- this.oauthService = oauthService;
413
+ constructor(tokenService, authConfig) {
414
+ this.tokenService = tokenService;
415
+ this.authConfig = authConfig;
452
416
  }
453
417
  intercept(req, next) {
454
- if (this.oauthService) {
455
- if (!this.isPathExcepted(req)) {
456
- const { token } = this.oauthService;
457
- if (token && token.access_token) {
458
- req = req.clone({
459
- setHeaders: {
460
- Authorization: `${token.token_type} ${token.access_token}`
461
- }
462
- });
463
- }
418
+ return this.tokenService.token$.pipe(take(1), map(token => {
419
+ if (token?.access_token && !this.isPathExcepted(req)) {
420
+ req = req.clone({
421
+ setHeaders: {
422
+ Authorization: `${token.token_type} ${token.access_token}`
423
+ }
424
+ });
464
425
  }
465
- return next.handle(req).pipe(catchError((err) => {
466
- if (err.status === 401 && !this.isPathExcepted(req)) {
467
- this.oauthService.token = null;
468
- this.oauthService.status = OAuthStatus.DENIED;
469
- }
470
- return throwError(err);
471
- }));
472
- }
473
- else {
474
- return next.handle(req);
475
- }
426
+ return req;
427
+ }), switchMap(req => next.handle(req)), catchError((err) => {
428
+ if (err.status === 401 && !this.isPathExcepted(req)) {
429
+ this.tokenService.token = {
430
+ error: `${err.status}`,
431
+ error_description: err.message
432
+ };
433
+ }
434
+ return throwError(() => err);
435
+ }));
476
436
  }
477
437
  isPathExcepted(req) {
478
- const { ignorePaths } = this.oauthService;
438
+ const { ignorePaths } = this.authConfig || {};
479
439
  if (ignorePaths) {
480
- for (const ignorePath of this.oauthService.ignorePaths) {
440
+ for (const ignorePath of ignorePaths) {
481
441
  try {
482
442
  if (req.url.match(ignorePath)) {
483
443
  return true;
@@ -490,39 +450,41 @@ class OAuthInterceptor {
490
450
  return false;
491
451
  }
492
452
  }
493
- OAuthInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthInterceptor, deps: [{ token: OAuthService }], target: i0.ɵɵFactoryTarget.Injectable });
494
- OAuthInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthInterceptor });
495
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthInterceptor, decorators: [{
453
+ OAuthInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthInterceptor, deps: [{ token: TokenService }, { token: OAuthConfig }], target: i0.ɵɵFactoryTarget.Injectable });
454
+ OAuthInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthInterceptor });
455
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthInterceptor, decorators: [{
496
456
  type: Injectable
497
- }], ctorParameters: function () { return [{ type: OAuthService }]; } });
457
+ }], ctorParameters: function () { return [{ type: TokenService }, { type: OAuthConfig }]; } });
498
458
 
459
+ var _OAuthLoginComponent_subscription, _OAuthLoginComponent_redirectUri, _OAuthLoginComponent_responseType, _OAuthLoginComponent_i18n;
499
460
  class OAuthLoginComponent {
500
461
  constructor(oauthService, locationService, location) {
501
462
  this.oauthService = oauthService;
502
463
  this.locationService = locationService;
503
464
  this.location = location;
504
- this.subscription = new Subscription();
505
- this._i18n = {
465
+ _OAuthLoginComponent_subscription.set(this, new Subscription());
466
+ _OAuthLoginComponent_redirectUri.set(this, void 0);
467
+ _OAuthLoginComponent_responseType.set(this, void 0);
468
+ _OAuthLoginComponent_i18n.set(this, {
506
469
  username: 'Username',
507
470
  password: 'Password',
508
471
  submit: 'Sign in',
509
472
  notAuthorized: 'Sign in',
510
473
  authorized: 'Welcome',
511
474
  denied: 'Access Denied. Try again!'
512
- };
475
+ });
476
+ this.type = OAuthType.RESOURCE;
513
477
  this.useLogoutUrl = false;
514
478
  this.state = '';
515
- this.stateChange = new EventEmitter();
479
+ this.stateChange = this.oauthService.state$.asObservable();
516
480
  this.username = '';
517
481
  this.password = '';
518
482
  this.OAuthStatus = OAuthStatus;
519
483
  this.OAuthType = OAuthType;
520
484
  this.collapse = false;
521
- this.type = this.oauthService.type;
522
- this.state$ = this.oauthService.state$.pipe(tap(s => this.stateChange.emit(s)));
523
485
  this.status$ = this.oauthService.status$.pipe(tap(s => {
524
486
  if (s === OAuthStatus.AUTHORIZED && this.profileName$) {
525
- this.subscription.add(this.profileName$.pipe(take(1)).subscribe(n => this.profileName = n));
487
+ __classPrivateFieldGet(this, _OAuthLoginComponent_subscription, "f").add(this.profileName$.pipe(take(1)).subscribe(n => this.profileName = n));
526
488
  }
527
489
  else {
528
490
  const { token } = this.oauthService;
@@ -534,31 +496,39 @@ class OAuthLoginComponent {
534
496
  this.logoutFunction = () => this.logout();
535
497
  }
536
498
  get i18n() {
537
- return this._i18n;
499
+ return __classPrivateFieldGet(this, _OAuthLoginComponent_i18n, "f");
538
500
  }
539
501
  set i18n(i18n) {
540
- this._i18n = {
541
- ...this._i18n,
502
+ __classPrivateFieldSet(this, _OAuthLoginComponent_i18n, {
503
+ ...__classPrivateFieldGet(this, _OAuthLoginComponent_i18n, "f"),
542
504
  ...i18n
543
- };
505
+ }, "f");
506
+ }
507
+ get redirectUri() {
508
+ return __classPrivateFieldGet(this, _OAuthLoginComponent_redirectUri, "f") || `${this.location.origin}${this.locationService.path(true) || '/'}`;
544
509
  }
545
510
  set redirectUri(redirectUri) {
546
511
  if (redirectUri) {
547
- this._redirectUri = redirectUri;
512
+ __classPrivateFieldSet(this, _OAuthLoginComponent_redirectUri, redirectUri, "f");
548
513
  }
549
514
  }
550
- get redirectUri() {
551
- return this._redirectUri || `${this.location.origin}${this.locationService.path(true) || '/'}`;
515
+ set responseType(responseType) {
516
+ if (this.responseType) {
517
+ __classPrivateFieldSet(this, _OAuthLoginComponent_responseType, responseType, "f");
518
+ }
519
+ }
520
+ get responseType() {
521
+ return __classPrivateFieldGet(this, _OAuthLoginComponent_responseType, "f") || this.type;
552
522
  }
553
523
  ngOnDestroy() {
554
- this.subscription.unsubscribe();
524
+ __classPrivateFieldGet(this, _OAuthLoginComponent_subscription, "f").unsubscribe();
555
525
  }
556
526
  logout() {
557
527
  this.oauthService.logout(this.useLogoutUrl);
558
528
  }
559
- async login(parameters) {
560
- await this.oauthService.login(parameters);
529
+ login(parameters) {
561
530
  this.collapse = false;
531
+ return this.oauthService.login(parameters);
562
532
  }
563
533
  toggleCollapse() {
564
534
  this.collapse = !this.collapse;
@@ -567,18 +537,23 @@ class OAuthLoginComponent {
567
537
  this.collapse = false;
568
538
  }
569
539
  }
570
- OAuthLoginComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthLoginComponent, deps: [{ token: OAuthService }, { token: i2.Location }, { token: LOCATION }], target: i0.ɵɵFactoryTarget.Component });
571
- OAuthLoginComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.5", type: OAuthLoginComponent, selector: "oauth-login", inputs: { i18n: "i18n", redirectUri: "redirectUri", useLogoutUrl: "useLogoutUrl", state: "state", profileName$: "profileName$" }, outputs: { stateChange: "stateChange" }, host: { listeners: { "window:keydown.escape": "keyboardEvent()" } }, queries: [{ propertyName: "loginTemplate", first: true, predicate: ["login"], descendants: true }], ngImport: i0, template: "<ng-container *ngIf=\"state$ | async\"></ng-container>\r\n<ng-container *ngIf=\"loginTemplate; else defaultLogin\"\r\n [ngTemplateOutlet]=\"loginTemplate\"\r\n [ngTemplateOutletContext]=\"{login: loginFunction, logout: logoutFunction, status: status$ | async}\">\r\n</ng-container>\r\n<ng-template #defaultLogin>\r\n <ng-container *ngIf=\"status$ | async as status\">\r\n <ng-container *ngIf=\"type === OAuthType.RESOURCE; else noResource\">\r\n <div class=\"oauth dropdown text-end p-3 {{collapse ? 'show': ''}}\">\r\n <button class=\"btn btn-link p-0 dropdown-toggle\"\r\n (click)=\"status === OAuthStatus.AUTHORIZED ? logout() : toggleCollapse()\">\r\n <ng-container *ngTemplateOutlet=\"message\"></ng-container>\r\n </button>\r\n <div class=\"dropdown-menu mr-3 {{collapse ? 'show': ''}}\">\r\n <form class=\"p-3\" #form=\"ngForm\"\r\n *ngIf=\"status === OAuthStatus.NOT_AUTHORIZED || status === OAuthStatus.DENIED\"\r\n (submit)=\"login({username: username, password: password})\">\r\n <div class=\"mb-3\">\r\n <input type=\"text\"\r\n class=\"form-control\"\r\n name=\"username\"\r\n required\r\n [(ngModel)]=\"username\"\r\n [placeholder]=\"i18n.username\">\r\n </div>\r\n <div class=\"mb-3\">\r\n <input type=\"password\"\r\n class=\"form-control\"\r\n name=\"password\"\r\n required\r\n [(ngModel)]=\"password\"\r\n [placeholder]=\"i18n.password\">\r\n </div>\r\n <div class=\"text-end\">\r\n <button type=\"submit\"\r\n class=\"btn btn-primary\"\r\n [disabled]=\"form.invalid\">{{i18n.submit}}</button>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template #noResource>\r\n <a role=\"button\" class=\"oauth\"\r\n (click)=\"status === OAuthStatus.AUTHORIZED ? logout() : login({redirectUri: redirectUri, state:state})\">\r\n <ng-container *ngTemplateOutlet=\"message\"></ng-container>\r\n </a>\r\n </ng-template>\r\n\r\n <ng-template #message>\r\n <span *ngIf=\"status === OAuthStatus.NOT_AUTHORIZED\" class=\"not-authorized\">{{i18n.notAuthorized}}</span>\r\n <span *ngIf=\"status === OAuthStatus.AUTHORIZED\" class=\"authorized\">\r\n <span class=\"welcome\">{{i18n.authorized}}&nbsp;</span>\r\n <strong class=\"profile-name\" [innerHTML]=\"profileName\"></strong>\r\n </span>\r\n <span *ngIf=\"status === OAuthStatus.DENIED\" class=\"denied\">{{i18n.denied}}</span>\r\n </ng-template>\r\n </ng-container>\r\n</ng-template>\r\n\r\n", styles: [".oauth .dropdown-menu{left:auto;right:0;box-shadow:0 5px 10px #0003;min-width:250px}.oauth .dropdown-menu:before{content:\"\";display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:#0003;position:absolute;top:-7px;left:auto;right:15px}.oauth .dropdown-menu:after{content:\"\";display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:auto;right:16px}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None });
572
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthLoginComponent, decorators: [{
540
+ _OAuthLoginComponent_subscription = new WeakMap(), _OAuthLoginComponent_redirectUri = new WeakMap(), _OAuthLoginComponent_responseType = new WeakMap(), _OAuthLoginComponent_i18n = new WeakMap();
541
+ OAuthLoginComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthLoginComponent, deps: [{ token: OAuthService }, { token: i2.Location }, { token: LOCATION }], target: i0.ɵɵFactoryTarget.Component });
542
+ OAuthLoginComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.3", type: OAuthLoginComponent, selector: "oauth-login", inputs: { type: "type", i18n: "i18n", redirectUri: "redirectUri", responseType: "responseType", useLogoutUrl: "useLogoutUrl", state: "state", profileName$: "profileName$" }, outputs: { stateChange: "stateChange" }, host: { listeners: { "window:keydown.escape": "keyboardEvent()" } }, queries: [{ propertyName: "loginTemplate", first: true, predicate: ["login"], descendants: true }], ngImport: i0, template: "<ng-container *ngIf=\"loginTemplate; else defaultLogin\"\r\n [ngTemplateOutlet]=\"loginTemplate\"\r\n [ngTemplateOutletContext]=\"{login: loginFunction, logout: logoutFunction, status: status$ | async}\">\r\n</ng-container>\r\n<ng-template #defaultLogin>\r\n <ng-container *ngIf=\"status$ | async as status\">\r\n <ng-container *ngIf=\"type === OAuthType.RESOURCE; else noResource\">\r\n <div class=\"oauth dropdown text-end {{collapse ? 'show': ''}}\">\r\n <button class=\"btn btn-link p-0 dropdown-toggle\"\r\n (click)=\"status === OAuthStatus.AUTHORIZED ? logout() : toggleCollapse()\">\r\n <ng-container *ngTemplateOutlet=\"message\"></ng-container>\r\n </button>\r\n <div class=\"dropdown-menu mr-3 {{collapse ? 'show': ''}}\">\r\n <form class=\"p-3\"\r\n #form=\"ngForm\"\r\n *ngIf=\"status === OAuthStatus.NOT_AUTHORIZED || status === OAuthStatus.DENIED\"\r\n (submit)=\"login({username: username, password: password})\">\r\n <div class=\"mb-3\">\r\n <input type=\"text\"\r\n class=\"form-control\"\r\n name=\"username\"\r\n required\r\n [(ngModel)]=\"username\"\r\n [placeholder]=\"i18n.username\">\r\n </div>\r\n <div class=\"mb-3\">\r\n <input type=\"password\"\r\n class=\"form-control\"\r\n name=\"password\"\r\n required\r\n [(ngModel)]=\"password\"\r\n [placeholder]=\"i18n.password\">\r\n </div>\r\n <div class=\"text-end\">\r\n <button type=\"submit\"\r\n class=\"btn btn-primary\"\r\n [disabled]=\"form.invalid\">{{i18n.submit}}</button>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template #noResource>\r\n <a role=\"button\"\r\n class=\"oauth\"\r\n (click)=\"status === OAuthStatus.AUTHORIZED ? logout() : login({responseType: responseType, redirectUri: redirectUri, state:state})\">\r\n <ng-container *ngTemplateOutlet=\"message\"></ng-container>\r\n </a>\r\n </ng-template>\r\n\r\n <ng-template #message>\r\n <span class=\"not-authorized\"\r\n *ngIf=\"status === OAuthStatus.NOT_AUTHORIZED\"\r\n [innerHTML]=\"i18n.notAuthorized\"></span>\r\n <span class=\"authorized\"\r\n *ngIf=\"status === OAuthStatus.AUTHORIZED\">\r\n <span class=\"welcome\" [innerHTML]=\"i18n.authorized + '&nbsp;'\"></span>\r\n <strong class=\"profile-name\"\r\n [innerHTML]=\"profileName\"></strong>\r\n </span>\r\n <span class=\"denied\"\r\n *ngIf=\"status === OAuthStatus.DENIED\"\r\n [innerHTML]=\"i18n.denied\"></span>\r\n </ng-template>\r\n </ng-container>\r\n</ng-template>\r\n\r\n", styles: [".oauth .dropdown-menu{left:auto;right:0;box-shadow:0 5px 10px #0003;min-width:250px}.oauth .dropdown-menu:before{content:\"\";display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:#0003;position:absolute;top:-7px;left:auto;right:15px}.oauth .dropdown-menu:after{content:\"\";display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:auto;right:16px}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None });
543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthLoginComponent, decorators: [{
573
544
  type: Component,
574
- args: [{ selector: 'oauth-login', encapsulation: ViewEncapsulation.None, template: "<ng-container *ngIf=\"state$ | async\"></ng-container>\r\n<ng-container *ngIf=\"loginTemplate; else defaultLogin\"\r\n [ngTemplateOutlet]=\"loginTemplate\"\r\n [ngTemplateOutletContext]=\"{login: loginFunction, logout: logoutFunction, status: status$ | async}\">\r\n</ng-container>\r\n<ng-template #defaultLogin>\r\n <ng-container *ngIf=\"status$ | async as status\">\r\n <ng-container *ngIf=\"type === OAuthType.RESOURCE; else noResource\">\r\n <div class=\"oauth dropdown text-end p-3 {{collapse ? 'show': ''}}\">\r\n <button class=\"btn btn-link p-0 dropdown-toggle\"\r\n (click)=\"status === OAuthStatus.AUTHORIZED ? logout() : toggleCollapse()\">\r\n <ng-container *ngTemplateOutlet=\"message\"></ng-container>\r\n </button>\r\n <div class=\"dropdown-menu mr-3 {{collapse ? 'show': ''}}\">\r\n <form class=\"p-3\" #form=\"ngForm\"\r\n *ngIf=\"status === OAuthStatus.NOT_AUTHORIZED || status === OAuthStatus.DENIED\"\r\n (submit)=\"login({username: username, password: password})\">\r\n <div class=\"mb-3\">\r\n <input type=\"text\"\r\n class=\"form-control\"\r\n name=\"username\"\r\n required\r\n [(ngModel)]=\"username\"\r\n [placeholder]=\"i18n.username\">\r\n </div>\r\n <div class=\"mb-3\">\r\n <input type=\"password\"\r\n class=\"form-control\"\r\n name=\"password\"\r\n required\r\n [(ngModel)]=\"password\"\r\n [placeholder]=\"i18n.password\">\r\n </div>\r\n <div class=\"text-end\">\r\n <button type=\"submit\"\r\n class=\"btn btn-primary\"\r\n [disabled]=\"form.invalid\">{{i18n.submit}}</button>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template #noResource>\r\n <a role=\"button\" class=\"oauth\"\r\n (click)=\"status === OAuthStatus.AUTHORIZED ? logout() : login({redirectUri: redirectUri, state:state})\">\r\n <ng-container *ngTemplateOutlet=\"message\"></ng-container>\r\n </a>\r\n </ng-template>\r\n\r\n <ng-template #message>\r\n <span *ngIf=\"status === OAuthStatus.NOT_AUTHORIZED\" class=\"not-authorized\">{{i18n.notAuthorized}}</span>\r\n <span *ngIf=\"status === OAuthStatus.AUTHORIZED\" class=\"authorized\">\r\n <span class=\"welcome\">{{i18n.authorized}}&nbsp;</span>\r\n <strong class=\"profile-name\" [innerHTML]=\"profileName\"></strong>\r\n </span>\r\n <span *ngIf=\"status === OAuthStatus.DENIED\" class=\"denied\">{{i18n.denied}}</span>\r\n </ng-template>\r\n </ng-container>\r\n</ng-template>\r\n\r\n", styles: [".oauth .dropdown-menu{left:auto;right:0;box-shadow:0 5px 10px #0003;min-width:250px}.oauth .dropdown-menu:before{content:\"\";display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:#0003;position:absolute;top:-7px;left:auto;right:15px}.oauth .dropdown-menu:after{content:\"\";display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:auto;right:16px}\n"] }]
545
+ args: [{ selector: 'oauth-login', encapsulation: ViewEncapsulation.None, template: "<ng-container *ngIf=\"loginTemplate; else defaultLogin\"\r\n [ngTemplateOutlet]=\"loginTemplate\"\r\n [ngTemplateOutletContext]=\"{login: loginFunction, logout: logoutFunction, status: status$ | async}\">\r\n</ng-container>\r\n<ng-template #defaultLogin>\r\n <ng-container *ngIf=\"status$ | async as status\">\r\n <ng-container *ngIf=\"type === OAuthType.RESOURCE; else noResource\">\r\n <div class=\"oauth dropdown text-end {{collapse ? 'show': ''}}\">\r\n <button class=\"btn btn-link p-0 dropdown-toggle\"\r\n (click)=\"status === OAuthStatus.AUTHORIZED ? logout() : toggleCollapse()\">\r\n <ng-container *ngTemplateOutlet=\"message\"></ng-container>\r\n </button>\r\n <div class=\"dropdown-menu mr-3 {{collapse ? 'show': ''}}\">\r\n <form class=\"p-3\"\r\n #form=\"ngForm\"\r\n *ngIf=\"status === OAuthStatus.NOT_AUTHORIZED || status === OAuthStatus.DENIED\"\r\n (submit)=\"login({username: username, password: password})\">\r\n <div class=\"mb-3\">\r\n <input type=\"text\"\r\n class=\"form-control\"\r\n name=\"username\"\r\n required\r\n [(ngModel)]=\"username\"\r\n [placeholder]=\"i18n.username\">\r\n </div>\r\n <div class=\"mb-3\">\r\n <input type=\"password\"\r\n class=\"form-control\"\r\n name=\"password\"\r\n required\r\n [(ngModel)]=\"password\"\r\n [placeholder]=\"i18n.password\">\r\n </div>\r\n <div class=\"text-end\">\r\n <button type=\"submit\"\r\n class=\"btn btn-primary\"\r\n [disabled]=\"form.invalid\">{{i18n.submit}}</button>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template #noResource>\r\n <a role=\"button\"\r\n class=\"oauth\"\r\n (click)=\"status === OAuthStatus.AUTHORIZED ? logout() : login({responseType: responseType, redirectUri: redirectUri, state:state})\">\r\n <ng-container *ngTemplateOutlet=\"message\"></ng-container>\r\n </a>\r\n </ng-template>\r\n\r\n <ng-template #message>\r\n <span class=\"not-authorized\"\r\n *ngIf=\"status === OAuthStatus.NOT_AUTHORIZED\"\r\n [innerHTML]=\"i18n.notAuthorized\"></span>\r\n <span class=\"authorized\"\r\n *ngIf=\"status === OAuthStatus.AUTHORIZED\">\r\n <span class=\"welcome\" [innerHTML]=\"i18n.authorized + '&nbsp;'\"></span>\r\n <strong class=\"profile-name\"\r\n [innerHTML]=\"profileName\"></strong>\r\n </span>\r\n <span class=\"denied\"\r\n *ngIf=\"status === OAuthStatus.DENIED\"\r\n [innerHTML]=\"i18n.denied\"></span>\r\n </ng-template>\r\n </ng-container>\r\n</ng-template>\r\n\r\n", styles: [".oauth .dropdown-menu{left:auto;right:0;box-shadow:0 5px 10px #0003;min-width:250px}.oauth .dropdown-menu:before{content:\"\";display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:#0003;position:absolute;top:-7px;left:auto;right:15px}.oauth .dropdown-menu:after{content:\"\";display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:auto;right:16px}\n"] }]
575
546
  }], ctorParameters: function () { return [{ type: OAuthService }, { type: i2.Location }, { type: Location, decorators: [{
576
547
  type: Inject,
577
548
  args: [LOCATION]
578
- }] }]; }, propDecorators: { i18n: [{
549
+ }] }]; }, propDecorators: { type: [{
550
+ type: Input
551
+ }], i18n: [{
579
552
  type: Input
580
553
  }], redirectUri: [{
581
554
  type: Input
555
+ }], responseType: [{
556
+ type: Input
582
557
  }], useLogoutUrl: [{
583
558
  type: Input
584
559
  }], state: [{
@@ -602,10 +577,10 @@ const mockLocation = (serverHost, serverPath) => {
602
577
  href, origin, protocol, host, hostname, port, pathname, search, hash,
603
578
  reload() {
604
579
  },
605
- assign(u) {
580
+ assign(_) {
606
581
  },
607
582
  ancestorOrigins: {},
608
- replace(u) {
583
+ replace(_) {
609
584
  }
610
585
  };
611
586
  };
@@ -642,6 +617,14 @@ const StorageService = {
642
617
  },
643
618
  deps: [PLATFORM_ID]
644
619
  };
620
+ const OAuthHttpClient = {
621
+ provide: OAUTH_HTTP_CLIENT,
622
+ useFactory(httpBackend) {
623
+ // avoid http interceptors
624
+ return new HttpClient(httpBackend);
625
+ },
626
+ deps: [HttpBackend]
627
+ };
645
628
  const OAuthInterceptorService = {
646
629
  provide: HTTP_INTERCEPTORS,
647
630
  useClass: OAuthInterceptor,
@@ -661,26 +644,28 @@ class OAuthModule {
661
644
  providers: [
662
645
  LocationService,
663
646
  StorageService,
664
- OAuthService,
665
- OAuthInterceptorService,
647
+ OAuthHttpClient,
666
648
  provideOAuthConfigFactory((storage) => ({
667
649
  ...defaultConfig(storage),
668
650
  ...config
669
651
  }), [STORAGE]),
652
+ TokenService,
653
+ OAuthInterceptorService,
654
+ OAuthService,
670
655
  ]
671
656
  };
672
657
  }
673
658
  }
674
- OAuthModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
675
- OAuthModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.5", ngImport: i0, type: OAuthModule, declarations: [OAuthLoginComponent], imports: [CommonModule,
659
+ OAuthModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
660
+ OAuthModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.3", ngImport: i0, type: OAuthModule, declarations: [OAuthLoginComponent], imports: [CommonModule,
676
661
  FormsModule,
677
662
  HttpClientModule,
678
663
  RouterModule], exports: [OAuthLoginComponent] });
679
- OAuthModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthModule, imports: [CommonModule,
664
+ OAuthModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthModule, imports: [CommonModule,
680
665
  FormsModule,
681
666
  HttpClientModule,
682
667
  RouterModule] });
683
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthModule, decorators: [{
668
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: OAuthModule, decorators: [{
684
669
  type: NgModule,
685
670
  args: [{
686
671
  imports: [
@@ -702,5 +687,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImpor
702
687
  * Generated bundle index. Do not edit.
703
688
  */
704
689
 
705
- export { LOCATION, OAUTH_CONFIG, OAUTH_TOKEN, OAuthConfig, OAuthInterceptor, OAuthLoginComponent, OAuthModule, OAuthService, OAuthStatus, OAuthType, SERVER_HOST, SERVER_PATH, STORAGE, provideOAuthConfig, provideOAuthConfigFactory };
690
+ export { HEADER_APPLICATION, LOCATION, OAUTH_CONFIG, OAUTH_HTTP_CLIENT, OAUTH_TOKEN, OAuthConfig, OAuthInterceptor, OAuthLoginComponent, OAuthModule, OAuthService, OAuthStatus, OAuthType, SERVER_HOST, SERVER_PATH, STORAGE, provideOAuthConfig, provideOAuthConfigFactory };
706
691
  //# sourceMappingURL=ngx-oauth.mjs.map