ngx-oauth 3.0.2 → 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, 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';
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, firstValueFrom, 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,7 @@ 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' });
19
21
  class OAuthConfig {
20
22
  }
21
23
  OAuthConfig.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -52,6 +54,77 @@ var OAuthStatus;
52
54
  OAuthStatus["DENIED"] = "DENIED";
53
55
  })(OAuthStatus || (OAuthStatus = {}));
54
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
+
55
128
  const arrToString = (buf) => buf.reduce((s, b) => s + String.fromCharCode(b), '');
56
129
  const base64url = (str) => btoa(str)
57
130
  .replace(/\+/g, '-')
@@ -65,7 +138,6 @@ const pkce = async (value) => {
65
138
  const buff = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value));
66
139
  return base64url(arrToString(new Uint8Array(buff)));
67
140
  };
68
- const REQUEST_HEADER = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });
69
141
  const parseOauthUri = (hash) => {
70
142
  const regex = /([^&=]+)=([^&]*)/g;
71
143
  const params = {};
@@ -74,81 +146,48 @@ const parseOauthUri = (hash) => {
74
146
  while ((m = regex.exec(hash)) !== null) {
75
147
  params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
76
148
  }
77
- if (Object.keys(params).length) {
78
- return params;
79
- }
80
- return null;
149
+ return Object.keys(params).length && params || {};
81
150
  };
82
151
  const jwt = (token) => JSON.parse(atob(token.split('.')[1]));
83
152
  class OAuthService {
84
- constructor(http, zone, authConfig, location, locationService) {
85
- this.http = http;
86
- this.zone = zone;
153
+ constructor(authConfig, tokenService, http, location, locationService) {
87
154
  this.authConfig = authConfig;
155
+ this.tokenService = tokenService;
156
+ this.http = http;
88
157
  this.location = location;
89
158
  this.locationService = locationService;
90
- this._token = null;
91
- this._status = OAuthStatus.NOT_AUTHORIZED;
92
159
  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 => {
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);
137
174
  if (isImplicitRedirect) {
138
- const parameters = parseOauthUri(hash.substr(1));
139
- this.token = parameters;
140
- 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);
141
181
  }
142
182
  else if (isAuthCodeRedirect) {
143
- const parameters = parseOauthUri(search.substr(1));
144
- if (!this.checkResponse(savedToken, parameters)) {
183
+ const parameters = parseOauthUri(search.substring(1));
184
+ if (!this.checkResponse(this.token, parameters)) {
145
185
  this.token = parameters;
146
- this.status = OAuthStatus.DENIED;
147
186
  }
148
187
  else {
149
188
  const newParametersString = this.getCleanedUnSearchParameters();
150
189
  const { clientId, clientSecret, tokenPath, scope } = config;
151
- const codeVerifier = savedToken && savedToken.codeVerifier;
190
+ const { codeVerifier } = this.token || {}; //should be set by autorizationUrl construction
152
191
  this.http.post(tokenPath, new HttpParams({
153
192
  fromObject: {
154
193
  code: parameters?.['code'],
@@ -159,56 +198,58 @@ class OAuthService {
159
198
  ...scope && { scope } || {},
160
199
  ...codeVerifier && { code_verifier: codeVerifier } || {}
161
200
  }
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;
201
+ }), { headers: HEADER_APPLICATION }).pipe().subscribe(token => {
202
+ this.token = {
203
+ ...token,
204
+ type: OAuthType.AUTHORIZATION_CODE
205
+ };
170
206
  this.locationService.replaceState(`${pathname}${newParametersString}`);
171
207
  });
172
208
  }
173
209
  }
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
- });
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 || [];
218
+ }
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
+ };
234
+ }
193
235
  }
194
236
  async login(parameters) {
195
- if (this.isResourceType(parameters)) {
237
+ if (!!parameters && parameters.password) {
196
238
  await this.resourceLogin(parameters);
197
239
  }
198
- else if (this.isAuthorizationCodeType(parameters)) {
199
- await this.authorizationCodeLogin(parameters);
240
+ else if (!!parameters
241
+ && parameters.redirectUri
242
+ && (parameters.responseType === OAuthType.IMPLICIT
243
+ || parameters.responseType === OAuthType.AUTHORIZATION_CODE)) {
244
+ await this.toAuthorizationUrl(parameters);
200
245
  }
201
- else if (this.isImplicitType(parameters)) {
202
- await this.implicitLogin(parameters);
203
- }
204
- else if (this.isClientCredentialType()) {
246
+ else {
205
247
  await this.clientCredentialLogin();
206
248
  }
207
249
  }
208
250
  logout(useLogoutUrl) {
209
251
  this.revoke();
210
- this.token = null;
211
- this.status = OAuthStatus.NOT_AUTHORIZED;
252
+ this.token = {};
212
253
  const { logoutPath, logoutRedirectUri } = this.authConfig.config;
213
254
  if (useLogoutUrl && logoutPath) {
214
255
  const { origin, pathname } = this.location;
@@ -219,7 +260,7 @@ class OAuthService {
219
260
  revoke() {
220
261
  const { revokePath, clientId, clientSecret } = this.authConfig.config;
221
262
  if (revokePath) {
222
- const { access_token, refresh_token } = this.token;
263
+ const { access_token, refresh_token } = this.token || {};
223
264
  const toRevoke = [];
224
265
  if (access_token) {
225
266
  toRevoke.push({
@@ -238,53 +279,32 @@ class OAuthService {
238
279
  });
239
280
  }
240
281
  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);
282
+ switchMap$1(o => this.http.post(revokePath, new HttpParams({ fromObject: o })))).subscribe(noop);
242
283
  }
243
284
  }
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() {
285
+ clientCredentialLogin() {
267
286
  const { clientId, clientSecret, tokenPath, scope } = this.authConfig.config;
268
- await firstValueFrom(this.http.post(tokenPath, new HttpParams({
287
+ return firstValueFrom(this.http.post(tokenPath, new HttpParams({
269
288
  fromObject: {
270
289
  client_id: clientId,
271
290
  client_secret: clientSecret,
272
291
  grant_type: OAuthType.CLIENT_CREDENTIAL,
273
292
  ...scope ? { scope } : {},
274
293
  }
275
- }), { headers: REQUEST_HEADER }).pipe(catchError((err) => {
294
+ }), { headers: HEADER_APPLICATION }).pipe(catchError((err) => {
276
295
  this.token = err;
277
- this.status = OAuthStatus.DENIED;
278
- return EMPTY;
296
+ return throwError(() => err);
279
297
  }), tap(params => {
280
- this.token = params;
281
- this.status = OAuthStatus.AUTHORIZED;
298
+ this.token = {
299
+ ...params,
300
+ type: OAuthType.CLIENT_CREDENTIAL,
301
+ };
282
302
  })));
283
303
  }
284
- async resourceLogin(parameters) {
304
+ resourceLogin(parameters) {
285
305
  const { clientId, clientSecret, tokenPath, scope } = this.authConfig.config;
286
306
  const { username, password } = parameters;
287
- await firstValueFrom(this.http.post(tokenPath, new HttpParams({
307
+ return firstValueFrom(this.http.post(tokenPath, new HttpParams({
288
308
  fromObject: {
289
309
  client_id: clientId,
290
310
  ...clientSecret && { client_secret: clientSecret } || {},
@@ -293,45 +313,26 @@ class OAuthService {
293
313
  username,
294
314
  password
295
315
  }
296
- }), { headers: REQUEST_HEADER }).pipe(catchError(err => {
316
+ }), { headers: HEADER_APPLICATION }).pipe(catchError(err => {
297
317
  this.token = err;
298
- this.status = OAuthStatus.DENIED;
299
- return EMPTY;
318
+ return throwError(() => err);
300
319
  }), tap(params => {
301
- this.token = params;
302
- this.status = OAuthStatus.AUTHORIZED;
320
+ this.token = {
321
+ ...params,
322
+ type: OAuthType.RESOURCE,
323
+ };
303
324
  })));
304
325
  }
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) {
326
+ async toAuthorizationUrl(parameters) {
326
327
  const { config } = this.authConfig;
327
328
  let authorizationUrl = `${config.authorizePath}`;
328
329
  authorizationUrl += config.authorizePath.includes('?') && '&' || '?';
329
330
  authorizationUrl += `client_id=${config.clientId}`;
330
331
  authorizationUrl += `&redirect_uri=${encodeURIComponent(parameters.redirectUri)}`;
331
- authorizationUrl += `&response_type=${responseType}`;
332
+ authorizationUrl += `&response_type=${parameters.responseType}`;
332
333
  authorizationUrl += `&scope=${encodeURIComponent(config.scope || '')}`;
333
334
  authorizationUrl += `&state=${encodeURIComponent(parameters.state || '')}`;
334
- return `${authorizationUrl}${this.generateNonce(config)}${await this.generateCodeChallenge(config)}`;
335
+ return this.location.replace(`${authorizationUrl}${this.generateNonce(config)}${await this.generateCodeChallenge(config)}`);
335
336
  }
336
337
  async generateCodeChallenge(config) {
337
338
  if (config.pkce) {
@@ -361,60 +362,11 @@ class OAuthService {
361
362
  }
362
363
  return parameters['access_token'] || parameters['code'];
363
364
  }
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
365
  getCleanedUnSearchParameters() {
414
366
  const { search } = this.location;
415
- let searchString = search.substr(1);
367
+ let searchString = search && search.substring(1) || '';
416
368
  const hashKeys = ['code', 'state', 'error', 'error_description', 'session_state', 'scope', 'authuser', 'prompt'];
417
- hashKeys.forEach((hashKey) => {
369
+ hashKeys.forEach(hashKey => {
418
370
  const re = new RegExp('&' + hashKey + '(=[^&]*)?|^' + hashKey + '(=[^&]*)?&?');
419
371
  searchString = searchString.replace(re, '');
420
372
  });
@@ -422,62 +374,57 @@ class OAuthService {
422
374
  }
423
375
  cleanLocationHash() {
424
376
  const { hash } = this.location;
425
- let curHash = hash.substr(1);
377
+ let curHash = hash && hash.substring(1) || '';
426
378
  const hashKeys = ['access_token', 'token_type', 'expires_in', 'scope', 'state', 'error', 'error_description', 'session_state', 'nonce'];
427
- hashKeys.forEach((hashKey) => {
379
+ hashKeys.forEach(hashKey => {
428
380
  const re = new RegExp('&' + hashKey + '(=[^&]*)?|^' + hashKey + '(=[^&]*)?&?');
429
381
  curHash = curHash.replace(re, '');
430
382
  });
431
383
  this.location.hash = curHash;
432
384
  }
433
385
  emitState(parameters) {
434
- const { state } = parameters;
435
- if (state) {
436
- this.state$.next(state);
437
- }
386
+ const { state } = parameters || {};
387
+ state && this.state$.next(state);
438
388
  }
439
389
  }
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 });
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 });
441
391
  OAuthService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthService });
442
392
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthService, decorators: [{
443
393
  type: Injectable
444
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i0.NgZone }, { type: OAuthConfig }, { type: Location, decorators: [{
394
+ }], ctorParameters: function () { return [{ type: OAuthConfig }, { type: TokenService }, { type: i2.HttpClient }, { type: Location, decorators: [{
445
395
  type: Inject,
446
396
  args: [LOCATION]
447
- }] }, { type: i2.Location }]; } });
397
+ }] }, { type: i2$1.Location }]; } });
448
398
 
449
399
  class OAuthInterceptor {
450
- constructor(oauthService) {
451
- this.oauthService = oauthService;
400
+ constructor(tokenService, authConfig) {
401
+ this.tokenService = tokenService;
402
+ this.authConfig = authConfig;
452
403
  }
453
404
  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
- }
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
+ });
464
412
  }
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
- }
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
+ }));
476
423
  }
477
424
  isPathExcepted(req) {
478
- const { ignorePaths } = this.oauthService;
425
+ const { ignorePaths } = this.authConfig || {};
479
426
  if (ignorePaths) {
480
- for (const ignorePath of this.oauthService.ignorePaths) {
427
+ for (const ignorePath of ignorePaths) {
481
428
  try {
482
429
  if (req.url.match(ignorePath)) {
483
430
  return true;
@@ -490,39 +437,40 @@ class OAuthInterceptor {
490
437
  return false;
491
438
  }
492
439
  }
493
- OAuthInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthInterceptor, deps: [{ token: OAuthService }], target: i0.ɵɵFactoryTarget.Injectable });
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 });
494
441
  OAuthInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthInterceptor });
495
442
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthInterceptor, decorators: [{
496
443
  type: Injectable
497
- }], ctorParameters: function () { return [{ type: OAuthService }]; } });
444
+ }], ctorParameters: function () { return [{ type: TokenService }, { type: OAuthConfig }]; } });
498
445
 
446
+ var _OAuthLoginComponent_subscription, _OAuthLoginComponent_redirectUri, _OAuthLoginComponent_i18n;
499
447
  class OAuthLoginComponent {
500
448
  constructor(oauthService, locationService, location) {
501
449
  this.oauthService = oauthService;
502
450
  this.locationService = locationService;
503
451
  this.location = location;
504
- this.subscription = new Subscription();
505
- this._i18n = {
452
+ _OAuthLoginComponent_subscription.set(this, new Subscription());
453
+ _OAuthLoginComponent_redirectUri.set(this, void 0);
454
+ _OAuthLoginComponent_i18n.set(this, {
506
455
  username: 'Username',
507
456
  password: 'Password',
508
457
  submit: 'Sign in',
509
458
  notAuthorized: 'Sign in',
510
459
  authorized: 'Welcome',
511
460
  denied: 'Access Denied. Try again!'
512
- };
461
+ });
513
462
  this.useLogoutUrl = false;
514
463
  this.state = '';
515
- this.stateChange = new EventEmitter();
464
+ this.stateChange = this.oauthService.state$.asObservable();
516
465
  this.username = '';
517
466
  this.password = '';
518
467
  this.OAuthStatus = OAuthStatus;
519
468
  this.OAuthType = OAuthType;
520
469
  this.collapse = false;
521
- this.type = this.oauthService.type;
522
- this.state$ = this.oauthService.state$.pipe(tap(s => this.stateChange.emit(s)));
470
+ this.type = OAuthType.RESOURCE;
523
471
  this.status$ = this.oauthService.status$.pipe(tap(s => {
524
472
  if (s === OAuthStatus.AUTHORIZED && this.profileName$) {
525
- 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));
526
474
  }
527
475
  else {
528
476
  const { token } = this.oauthService;
@@ -534,31 +482,31 @@ class OAuthLoginComponent {
534
482
  this.logoutFunction = () => this.logout();
535
483
  }
536
484
  get i18n() {
537
- return this._i18n;
485
+ return __classPrivateFieldGet(this, _OAuthLoginComponent_i18n, "f");
538
486
  }
539
487
  set i18n(i18n) {
540
- this._i18n = {
541
- ...this._i18n,
488
+ __classPrivateFieldSet(this, _OAuthLoginComponent_i18n, {
489
+ ...__classPrivateFieldGet(this, _OAuthLoginComponent_i18n, "f"),
542
490
  ...i18n
543
- };
491
+ }, "f");
492
+ }
493
+ get redirectUri() {
494
+ return __classPrivateFieldGet(this, _OAuthLoginComponent_redirectUri, "f") || `${this.location.origin}${this.locationService.path(true) || '/'}`;
544
495
  }
545
496
  set redirectUri(redirectUri) {
546
497
  if (redirectUri) {
547
- this._redirectUri = redirectUri;
498
+ __classPrivateFieldSet(this, _OAuthLoginComponent_redirectUri, redirectUri, "f");
548
499
  }
549
500
  }
550
- get redirectUri() {
551
- return this._redirectUri || `${this.location.origin}${this.locationService.path(true) || '/'}`;
552
- }
553
501
  ngOnDestroy() {
554
- this.subscription.unsubscribe();
502
+ __classPrivateFieldGet(this, _OAuthLoginComponent_subscription, "f").unsubscribe();
555
503
  }
556
504
  logout() {
557
505
  this.oauthService.logout(this.useLogoutUrl);
558
506
  }
559
- async login(parameters) {
560
- await this.oauthService.login(parameters);
507
+ login(parameters) {
561
508
  this.collapse = false;
509
+ return this.oauthService.login(parameters);
562
510
  }
563
511
  toggleCollapse() {
564
512
  this.collapse = !this.collapse;
@@ -566,13 +514,17 @@ class OAuthLoginComponent {
566
514
  keyboardEvent() {
567
515
  this.collapse = false;
568
516
  }
517
+ get responseType() {
518
+ return this.type; //avoid complains
519
+ }
569
520
  }
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 });
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 });
572
524
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImport: i0, type: OAuthLoginComponent, decorators: [{
573
525
  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"] }]
575
- }], 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: [{
576
528
  type: Inject,
577
529
  args: [LOCATION]
578
530
  }] }]; }, propDecorators: { i18n: [{
@@ -590,6 +542,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImpor
590
542
  }], loginTemplate: [{
591
543
  type: ContentChild,
592
544
  args: ['login', { static: false }]
545
+ }], type: [{
546
+ type: Input
593
547
  }], keyboardEvent: [{
594
548
  type: HostListener,
595
549
  args: ['window:keydown.escape']
@@ -602,10 +556,10 @@ const mockLocation = (serverHost, serverPath) => {
602
556
  href, origin, protocol, host, hostname, port, pathname, search, hash,
603
557
  reload() {
604
558
  },
605
- assign(u) {
559
+ assign(_) {
606
560
  },
607
561
  ancestorOrigins: {},
608
- replace(u) {
562
+ replace(_) {
609
563
  }
610
564
  };
611
565
  };
@@ -661,12 +615,13 @@ class OAuthModule {
661
615
  providers: [
662
616
  LocationService,
663
617
  StorageService,
664
- OAuthService,
665
- OAuthInterceptorService,
666
618
  provideOAuthConfigFactory((storage) => ({
667
619
  ...defaultConfig(storage),
668
620
  ...config
669
621
  }), [STORAGE]),
622
+ TokenService,
623
+ OAuthInterceptorService,
624
+ OAuthService,
670
625
  ]
671
626
  };
672
627
  }
@@ -702,5 +657,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.5", ngImpor
702
657
  * Generated bundle index. Do not edit.
703
658
  */
704
659
 
705
- export { LOCATION, OAUTH_CONFIG, OAUTH_TOKEN, OAuthConfig, OAuthInterceptor, OAuthLoginComponent, OAuthModule, OAuthService, OAuthStatus, OAuthType, SERVER_HOST, SERVER_PATH, STORAGE, provideOAuthConfig, provideOAuthConfigFactory };
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