ngx-oauth 3.0.0 → 4.0.0

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