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