@odx/auth 14.0.0 → 15.0.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/CHANGELOG.md +17 -0
- package/esm2022/lib/auth.component.mjs +9 -4
- package/esm2022/lib/auth.config.mjs +38 -1
- package/esm2022/lib/auth.directive.mjs +14 -4
- package/esm2022/lib/auth.guard.mjs +9 -1
- package/esm2022/lib/auth.interceptor.mjs +8 -1
- package/esm2022/lib/auth.module.mjs +4 -4
- package/esm2022/lib/auth.providers.mjs +35 -1
- package/esm2022/lib/auth.service.mjs +162 -4
- package/esm2022/lib/components/auth-actions/auth-actions.component.mjs +13 -4
- package/esm2022/lib/components/auth-loading-screen/auth-loading-screen.component.mjs +18 -6
- package/esm2022/lib/directives/auth-action.directive.mjs +10 -4
- package/esm2022/lib/directives/sign-in.directive.mjs +23 -4
- package/esm2022/lib/directives/sign-out.directive.mjs +23 -4
- package/esm2022/lib/helpers/create-auth-host-url.mjs +13 -1
- package/esm2022/lib/helpers/create-inititals.mjs +18 -1
- package/esm2022/lib/helpers/handle-auth-error.mjs +13 -3
- package/esm2022/lib/helpers/handle-oauth-event.mjs +9 -1
- package/esm2022/lib/helpers/resolve-email.mjs +21 -1
- package/esm2022/lib/helpers/resolve-username.mjs +22 -1
- package/esm2022/lib/helpers/set-http-auth-header.mjs +10 -1
- package/esm2022/lib/helpers/user-language-loader.mjs +8 -1
- package/esm2022/lib/models/auth-plugin-manager.mjs +3 -3
- package/esm2022/lib/plugins/core-debug.plugin.mjs +10 -1
- package/esm2022/lib/plugins/core-identity.plugin.mjs +8 -1
- package/esm2022/lib/plugins/user-profile-link.plugin.mjs +10 -1
- package/esm2022/lib/unauth.guard.mjs +9 -1
- package/esm2022/plugins/service-connect/lib/helpers/build-service-connect-url.mjs +8 -1
- package/esm2022/plugins/service-connect/lib/helpers/has-roles-or-rights-handler.mjs +8 -1
- package/esm2022/plugins/service-connect/lib/helpers/has-roles-or-rights.mjs +8 -1
- package/esm2022/plugins/service-connect/lib/helpers/service-connect-plugin-factory.mjs +7 -1
- package/esm2022/plugins/service-connect/lib/service-connect-rights.directive.mjs +16 -4
- package/esm2022/plugins/service-connect/lib/service-connect-rights.guard.mjs +9 -1
- package/esm2022/plugins/service-connect/lib/service-connect-rights.plugin.mjs +9 -1
- package/esm2022/plugins/service-connect/lib/service-connect-user-language.plugin.mjs +15 -1
- package/esm2022/plugins/service-connect/lib/service-connect-user-profile.plugin.mjs +9 -1
- package/fesm2022/odx-auth-plugins-service-connect.mjs +80 -3
- package/fesm2022/odx-auth-plugins-service-connect.mjs.map +1 -1
- package/fesm2022/odx-auth.mjs +497 -36
- package/fesm2022/odx-auth.mjs.map +1 -1
- package/lib/auth.component.d.ts +5 -0
- package/lib/auth.config.d.ts +43 -1
- package/lib/auth.directive.d.ts +10 -0
- package/lib/auth.guard.d.ts +8 -0
- package/lib/auth.interceptor.d.ts +7 -0
- package/lib/auth.providers.d.ts +34 -0
- package/lib/auth.service.d.ts +156 -0
- package/lib/components/auth-actions/auth-actions.component.d.ts +9 -0
- package/lib/components/auth-loading-screen/auth-loading-screen.component.d.ts +13 -0
- package/lib/directives/auth-action.directive.d.ts +6 -0
- package/lib/directives/sign-in.directive.d.ts +19 -0
- package/lib/directives/sign-out.directive.d.ts +19 -0
- package/lib/helpers/create-auth-host-url.d.ts +12 -0
- package/lib/helpers/create-inititals.d.ts +17 -0
- package/lib/helpers/handle-auth-error.d.ts +10 -0
- package/lib/helpers/handle-oauth-event.d.ts +8 -0
- package/lib/helpers/resolve-email.d.ts +20 -0
- package/lib/helpers/resolve-username.d.ts +21 -0
- package/lib/helpers/set-http-auth-header.d.ts +9 -0
- package/lib/helpers/user-language-loader.d.ts +7 -0
- package/lib/plugins/core-debug.plugin.d.ts +9 -0
- package/lib/plugins/core-identity.plugin.d.ts +7 -0
- package/lib/plugins/user-profile-link.plugin.d.ts +9 -0
- package/lib/unauth.guard.d.ts +8 -0
- package/package.json +2 -2
- package/plugins/service-connect/lib/helpers/build-service-connect-url.d.ts +7 -0
- package/plugins/service-connect/lib/helpers/has-roles-or-rights-handler.d.ts +7 -0
- package/plugins/service-connect/lib/helpers/has-roles-or-rights.d.ts +7 -0
- package/plugins/service-connect/lib/helpers/service-connect-plugin-factory.d.ts +6 -0
- package/plugins/service-connect/lib/service-connect-rights.directive.d.ts +12 -0
- package/plugins/service-connect/lib/service-connect-rights.guard.d.ts +8 -0
- package/plugins/service-connect/lib/service-connect-rights.plugin.d.ts +8 -0
- package/plugins/service-connect/lib/service-connect-user-language.plugin.d.ts +14 -0
- package/plugins/service-connect/lib/service-connect-user-profile.plugin.d.ts +8 -0
package/fesm2022/odx-auth.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i1 from '@angular/common';
|
|
2
2
|
import { CommonModule, AsyncPipe, NgIf } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { inject, EnvironmentInjector, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, DestroyRef, InjectionToken, ENVIRONMENT_INITIALIZER, makeEnvironmentProviders, APP_INITIALIZER, Injectable, Directive, EventEmitter, Output, HostListener, input, NgModule } from '@angular/core';
|
|
4
|
+
import { inject, EnvironmentInjector, runInInjectionContext, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, DestroyRef, InjectionToken, ENVIRONMENT_INITIALIZER, makeEnvironmentProviders, APP_INITIALIZER, Injectable, Directive, EventEmitter, Output, HostListener, input, NgModule } from '@angular/core';
|
|
5
5
|
import * as i2$1 from '@odx/angular/components/area-header';
|
|
6
6
|
import { AreaHeaderModule } from '@odx/angular/components/area-header';
|
|
7
7
|
import * as i7 from '@odx/angular/components/dropdown';
|
|
@@ -27,17 +27,45 @@ import * as i3 from '@odx/angular/components/icon';
|
|
|
27
27
|
import { IconComponent } from '@odx/angular/components/icon';
|
|
28
28
|
import { trigger, transition, useAnimation } from '@angular/animations';
|
|
29
29
|
import { fadeOut } from '@odx/angular/animations';
|
|
30
|
-
import * as i5 from '@odx/angular/components/button';
|
|
31
|
-
import { ButtonComponent } from '@odx/angular/components/button';
|
|
32
30
|
import { CircularProgressComponent } from '@odx/angular/components/circular-progress';
|
|
33
31
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
34
32
|
import * as i3$1 from '@odx/angular/components/avatar';
|
|
35
33
|
import * as i4 from '@odx/angular/components/action-group';
|
|
34
|
+
import * as i5 from '@odx/angular/components/button';
|
|
36
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Creates an authentication host URL based on the provided environment and URL segments.
|
|
38
|
+
*
|
|
39
|
+
* @param {AuthEnvironment} environment - The authentication environment (e.g., 'development', 'production').
|
|
40
|
+
* @param {string[]} segments - Additional URL segments to append to the base URL.
|
|
41
|
+
* @returns {string} The constructed authentication host URL.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* createAuthHostUrl('dev', 'api', 'v1', 'users'); // returns 'https://dev-auth.odx.com/api/v1/users'
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
37
48
|
function createAuthHostUrl(environment, ...segments) {
|
|
38
49
|
return buildUrl(ODX_AUTH_HOSTS[environment], ...segments);
|
|
39
50
|
}
|
|
40
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Creates initials from a given string.
|
|
54
|
+
*
|
|
55
|
+
* This function takes a string input, removes any text within parentheses,
|
|
56
|
+
* trims any leading or trailing whitespace, and then splits the string into
|
|
57
|
+
* parts based on spaces. It then constructs initials using the first letter
|
|
58
|
+
* of the first and last parts of the string, converting them to uppercase.
|
|
59
|
+
*
|
|
60
|
+
* @param {string | null} value - The input string from which to create initials. It can be
|
|
61
|
+
* undefined or null, in which case an empty string is returned.
|
|
62
|
+
* @returns {string} - A string containing the initials derived from the input string.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* createInitials('John Smith'); // returns 'JS'
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
41
69
|
function createInitials(value) {
|
|
42
70
|
if (!value)
|
|
43
71
|
return '';
|
|
@@ -53,10 +81,20 @@ function createInitials(value) {
|
|
|
53
81
|
}, '');
|
|
54
82
|
}
|
|
55
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Handles authentication errors by executing a series of error handler functions.
|
|
86
|
+
*
|
|
87
|
+
* @param {AuthErrorHandlerFn[]} handlers - An array of functions that handle authentication errors.
|
|
88
|
+
* Each function is expected to take an `OAuthErrorEvent` as an argument.
|
|
89
|
+
*
|
|
90
|
+
* @returns A function that takes an `OAuthErrorEvent` and processes it using the provided handlers.
|
|
91
|
+
* The function will stop processing once a handler successfully handles the error without throwing.
|
|
92
|
+
* If a handler throws an error that is not an instance of `OAuthErrorEvent`, the original error is re-thrown.
|
|
93
|
+
*/
|
|
56
94
|
function handleAuthError(handlers) {
|
|
57
95
|
const injector = inject(EnvironmentInjector);
|
|
58
96
|
return (error) => {
|
|
59
|
-
injector
|
|
97
|
+
runInInjectionContext(injector, () => {
|
|
60
98
|
for (const handler of handlers) {
|
|
61
99
|
try {
|
|
62
100
|
handler(error);
|
|
@@ -72,10 +110,38 @@ function handleAuthError(handlers) {
|
|
|
72
110
|
};
|
|
73
111
|
}
|
|
74
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Handles OAuth events of a specific type by applying a provided handler function.
|
|
115
|
+
*
|
|
116
|
+
* @template {T} - The type of OAuth event.
|
|
117
|
+
* @param {T['type']} type - The type of the OAuth event to handle.
|
|
118
|
+
* @param {(event: T) => Promise<void>} handler - A function that takes an event of type T and returns a Promise that resolves to void.
|
|
119
|
+
* @returns {OperatorFunction<T, void>} - An OperatorFunction that filters events of the specified type and applies the handler function.
|
|
120
|
+
*/
|
|
75
121
|
function handleOAuthEvent(type, handler) {
|
|
76
122
|
return (source$) => source$.pipe(filter((event) => event.type === type), switchMap((event) => handler(event)));
|
|
77
123
|
}
|
|
78
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Resolves the email address from the given identity claims.
|
|
127
|
+
*
|
|
128
|
+
* This function attempts to extract an email address from the provided
|
|
129
|
+
* `OdxAuth.RawIdentityClaims` object by checking the following properties
|
|
130
|
+
* in order:
|
|
131
|
+
* 1. `email` - if it is a string, it is returned.
|
|
132
|
+
* 2. `email_address` - if it is a string, it is returned.
|
|
133
|
+
* 3. `emails` - if it is an array and the first element is a string, the first element is returned.
|
|
134
|
+
*
|
|
135
|
+
* If none of these properties contain a valid string email address, an empty string is returned.
|
|
136
|
+
*
|
|
137
|
+
* @param {OdxAuth.RawIdentityClaims} claims - The identity claims object from which to resolve the email address.
|
|
138
|
+
* @returns {string} - The resolved email address as a string, or an empty string if no valid email address is found.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* resolveEmail({ email_address: 'email.address@mdn.com' }) // returns 'email.address@mdn.com';
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
79
145
|
function resolveEmail(claims) {
|
|
80
146
|
if (isString(claims['email'])) {
|
|
81
147
|
return claims['email'];
|
|
@@ -89,6 +155,27 @@ function resolveEmail(claims) {
|
|
|
89
155
|
return '';
|
|
90
156
|
}
|
|
91
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Resolves the username from the provided identity claims.
|
|
160
|
+
*
|
|
161
|
+
* The function attempts to construct a username from the claims in the following order:
|
|
162
|
+
* 1. If both 'firstname' and 'lastname' are strings, it returns them concatenated with a space.
|
|
163
|
+
* 2. If both 'given_name' and 'family_name' are strings, it returns them concatenated with a space.
|
|
164
|
+
* 3. If 'name' is a string, it returns the 'name'.
|
|
165
|
+
* 4. If 'displayname' is a string, it returns the 'displayname'.
|
|
166
|
+
* 5. If none of the above conditions are met, it returns an empty string.
|
|
167
|
+
*
|
|
168
|
+
* @param {OdxAuth.RawIdentityClaims} claims - The raw identity claims from which to resolve the username.
|
|
169
|
+
* @returns {string} - The resolved username as a string.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* resolveUsername({ firstname: 'John', lastname: 'Doe' }) // returns 'John Doe';
|
|
174
|
+
* resolveUsername({ given_name: 'John', family_name: 'Doe' }) // returns 'John Doe';
|
|
175
|
+
* resolveUsername({ name: 'John Doe' }) // returns 'John Doe';
|
|
176
|
+
* resolveUsername({ displayname: 'John Doe' }) // returns 'John Doe';
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
92
179
|
function resolveUsername(claims) {
|
|
93
180
|
if (isString(claims['firstname']) && isString(claims['lastname'])) {
|
|
94
181
|
return `${claims['firstname']} ${claims['lastname']}`;
|
|
@@ -105,6 +192,15 @@ function resolveUsername(claims) {
|
|
|
105
192
|
return '';
|
|
106
193
|
}
|
|
107
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Sets the HTTP Authorization header for a given request.
|
|
197
|
+
*
|
|
198
|
+
* @template R - The type of the request, which extends HttpRequest<T> or Request.
|
|
199
|
+
* @template T - The type of the request body.
|
|
200
|
+
* @param {R} req - The HTTP request to which the Authorization header will be added.
|
|
201
|
+
* @param {string | null} [token] - The token to be used in the Authorization header. If no token is provided, the request is returned unchanged.
|
|
202
|
+
* @returns {R} - The modified HTTP request with the Authorization header set, or the original request if no token is provided.
|
|
203
|
+
*/
|
|
108
204
|
function setHttpAuthHeader(req, token) {
|
|
109
205
|
if (!token)
|
|
110
206
|
return req;
|
|
@@ -119,6 +215,13 @@ function setHttpAuthHeader(req, token) {
|
|
|
119
215
|
const AuthEnvironment = Environment;
|
|
120
216
|
|
|
121
217
|
const requireAuthentication = new HttpContextToken(() => false);
|
|
218
|
+
/**
|
|
219
|
+
* Interceptor to handle authentication for HTTP requests.
|
|
220
|
+
*
|
|
221
|
+
* This interceptor checks if the request URL is allowed or if the request requires authentication.
|
|
222
|
+
* If the URL is not allowed and the request does not require authentication, it simply forwards the request.
|
|
223
|
+
* Otherwise, it prepares the authentication request using the AuthService.
|
|
224
|
+
*/
|
|
122
225
|
const authInterceptor = (req, next) => {
|
|
123
226
|
const { allowedUrls, requireSignInForRequests } = injectAuthConfig();
|
|
124
227
|
const isUrlAllowed = allowedUrls.some((allowedUrl) => matchUrl(req.url, allowedUrl));
|
|
@@ -130,30 +233,52 @@ const authInterceptor = (req, next) => {
|
|
|
130
233
|
|
|
131
234
|
var logger = new Logger('@odx/auth');
|
|
132
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Displays authentication actions.
|
|
238
|
+
*/
|
|
133
239
|
let AuthActionsComponent = class AuthActionsComponent {
|
|
134
240
|
constructor() {
|
|
135
241
|
this.element = injectElement();
|
|
242
|
+
/**
|
|
243
|
+
* The identity claims.
|
|
244
|
+
*
|
|
245
|
+
* @type {OdxAuth.IdentiyClaims | null}
|
|
246
|
+
* @default null
|
|
247
|
+
*/
|
|
136
248
|
this.claims = null;
|
|
137
249
|
}
|
|
138
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
139
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
250
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
251
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: AuthActionsComponent, isStandalone: true, selector: "odx-auth-actions", inputs: { claims: "claims" }, ngImport: i0, template: "<odx-list>\n @if (claims?.userProfileUrl; as url) {\n <a data-testid=\"odx-auth-user-profile-link\" odxListItem [href]=\"url\" rel=\"noopener\" target=\"_blank\">\n <odx-icon name=\"user-administration\" iconSet=\"core\" odxListItemPrefix />\n {{ 'userProfileLink' | odxTranslate | async }}\n <odx-icon name=\"link-external\" iconSet=\"core\" size=\"small\" odxListItemSuffix />\n </a>\n }\n</odx-list>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ListModule }, { kind: "component", type: i2.ListComponent, selector: "odx-list" }, { kind: "component", type: i2.ListItemComponent, selector: "odx-list-item, [odxListItem]", inputs: ["danger", "variant", "muted", "selected"] }, { kind: "component", type: i3.IconComponent, selector: "odx-icon", inputs: ["inline", "size", "name", "iconSet", "identifier"] }, { kind: "pipe", type: TranslatePipe, name: "odxTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
140
252
|
};
|
|
141
253
|
AuthActionsComponent = __decorate([
|
|
142
254
|
CSSComponent('auth-actions')
|
|
143
255
|
], AuthActionsComponent);
|
|
144
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
256
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthActionsComponent, decorators: [{
|
|
145
257
|
type: Component,
|
|
146
258
|
args: [{ standalone: true, selector: 'odx-auth-actions', imports: [CoreModule, ListModule, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<odx-list>\n @if (claims?.userProfileUrl; as url) {\n <a data-testid=\"odx-auth-user-profile-link\" odxListItem [href]=\"url\" rel=\"noopener\" target=\"_blank\">\n <odx-icon name=\"user-administration\" iconSet=\"core\" odxListItemPrefix />\n {{ 'userProfileLink' | odxTranslate | async }}\n <odx-icon name=\"link-external\" iconSet=\"core\" size=\"small\" odxListItemSuffix />\n </a>\n }\n</odx-list>\n" }]
|
|
147
259
|
}], propDecorators: { claims: [{
|
|
148
260
|
type: Input
|
|
149
261
|
}] } });
|
|
150
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Authentication loading screen.
|
|
265
|
+
*
|
|
266
|
+
* This component displays a loading screen with animations and dynamic content
|
|
267
|
+
* based on the authentication state.
|
|
268
|
+
*/
|
|
151
269
|
class AuthLoadingScreenComponent {
|
|
152
270
|
constructor() {
|
|
153
271
|
this.authConfig = injectAuthConfig();
|
|
154
272
|
this.icon$ = inject(AuthService).isRedirecting$.pipe(map((isRedirecting) => (isRedirecting ? 'link-external' : 'user')));
|
|
155
273
|
}
|
|
156
274
|
static { this.instance = null; }
|
|
275
|
+
/**
|
|
276
|
+
* Initializes the authentication loading screen.
|
|
277
|
+
*
|
|
278
|
+
* @param {AuthService} authService - The authentication service.
|
|
279
|
+
* @param {DynamicViewService} dynamicViewService - The dynamic view service used to create the loading screen.
|
|
280
|
+
* @static
|
|
281
|
+
*/
|
|
157
282
|
static initialize(authService, dynamicViewService) {
|
|
158
283
|
authService.isLoading$.subscribe((isLoading) => {
|
|
159
284
|
if (isLoading) {
|
|
@@ -165,16 +290,25 @@ class AuthLoadingScreenComponent {
|
|
|
165
290
|
}
|
|
166
291
|
});
|
|
167
292
|
}
|
|
168
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
169
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
293
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthLoadingScreenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
294
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: AuthLoadingScreenComponent, isStandalone: true, selector: "div.odx-auth-loading-screen", host: { properties: { "@hostAnimation": "true" } }, ngImport: i0, template: "<div class=\"odx-auth-loading-screen__content\" odxLayout=\"grid 12 horizontal-center vertical-center gap-small\">\n <odx-logo size=\"large\" />\n <odx-circular-progress class=\"odx-auth-loading-screen__spinner\" value=\"-1\" size=\"medium\" stroke=\"3\">\n <odx-icon [name]=\"icon$ | async\" iconSet=\"core\" />\n </odx-circular-progress>\n @if (authConfig.loadingScreenMessage; as content) {\n <p class=\"odx-auth-loading-screen__message\">\n <ng-template [odxDynamicView]=\"content\" />\n </p>\n }\n</div>\n", styles: ["@keyframes odx-auth-loading-screen-animation{0%{opacity:0;transform:translate(-50%,-50%) scale(.9)}to{opacity:1;transform:translate(-50%,-50%)}}.odx-auth-loading-screen{--odx-c-highlight: var(--odx-c-primary);background-color:var(--odx-c-background-content);inset:0;position:fixed;z-index:var(--odx-v-layer-6)}.odx-auth-loading-screen__content{animation:odx-auth-loading-screen-animation .75s ease;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.odx-auth-loading-screen__message{text-align:center}.odx-auth-loading-screen__spinner{position:relative}.odx-auth-loading-screen__spinner .odx-icon{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "component", type: IconComponent, selector: "odx-icon", inputs: ["inline", "size", "name", "iconSet", "identifier"] }, { kind: "directive", type: LogoDirective, selector: "odx-logo", inputs: ["size", "variant"] }, { kind: "component", type: CircularProgressComponent, selector: "odx-circular-progress", inputs: ["stroke", "size", "value"] }, { kind: "directive", type: DynamicViewDirective, selector: "ng-template[odxDynamicView]", inputs: ["odxDynamicView", "odxDynamicViewInjector", "odxDynamicViewContext"] }], animations: [trigger('hostAnimation', [transition(':leave', useAnimation(fadeOut()))])], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
170
295
|
}
|
|
171
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
296
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthLoadingScreenComponent, decorators: [{
|
|
172
297
|
type: Component,
|
|
173
|
-
args: [{ standalone: true, selector: 'div.odx-auth-loading-screen', imports: [CommonModule,
|
|
298
|
+
args: [{ standalone: true, selector: 'div.odx-auth-loading-screen', imports: [CommonModule, IconComponent, LogoDirective, CircularProgressComponent, DynamicViewDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
|
|
174
299
|
'[@hostAnimation]': 'true',
|
|
175
300
|
}, animations: [trigger('hostAnimation', [transition(':leave', useAnimation(fadeOut()))])], template: "<div class=\"odx-auth-loading-screen__content\" odxLayout=\"grid 12 horizontal-center vertical-center gap-small\">\n <odx-logo size=\"large\" />\n <odx-circular-progress class=\"odx-auth-loading-screen__spinner\" value=\"-1\" size=\"medium\" stroke=\"3\">\n <odx-icon [name]=\"icon$ | async\" iconSet=\"core\" />\n </odx-circular-progress>\n @if (authConfig.loadingScreenMessage; as content) {\n <p class=\"odx-auth-loading-screen__message\">\n <ng-template [odxDynamicView]=\"content\" />\n </p>\n }\n</div>\n", styles: ["@keyframes odx-auth-loading-screen-animation{0%{opacity:0;transform:translate(-50%,-50%) scale(.9)}to{opacity:1;transform:translate(-50%,-50%)}}.odx-auth-loading-screen{--odx-c-highlight: var(--odx-c-primary);background-color:var(--odx-c-background-content);inset:0;position:fixed;z-index:var(--odx-v-layer-6)}.odx-auth-loading-screen__content{animation:odx-auth-loading-screen-animation .75s ease;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.odx-auth-loading-screen__message{text-align:center}.odx-auth-loading-screen__spinner{position:relative}.odx-auth-loading-screen__spinner .odx-icon{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}\n"] }]
|
|
176
301
|
}] });
|
|
177
302
|
|
|
303
|
+
/**
|
|
304
|
+
* A factory function that creates a core debug plugin for the authentication service.
|
|
305
|
+
* This plugin logs detailed information about the user's identity claims and tokens.
|
|
306
|
+
*
|
|
307
|
+
* @remarks
|
|
308
|
+
* This plugin is intended for debugging purposes only and should not be used in production environments.
|
|
309
|
+
*
|
|
310
|
+
* @returns {AuthPluginFactory} A function that takes an authentication service and sets up logging for identity claims and tokens.
|
|
311
|
+
*/
|
|
178
312
|
const coreDebugPlugin = () => {
|
|
179
313
|
logger.warn('DEBUG MODE ENABLED - DO NOT USE IN PRODUCTION!');
|
|
180
314
|
const destroyRef = inject(DestroyRef);
|
|
@@ -191,6 +325,13 @@ const coreDebugPlugin = () => {
|
|
|
191
325
|
};
|
|
192
326
|
};
|
|
193
327
|
|
|
328
|
+
/**
|
|
329
|
+
* Core identity plugin for authentication.
|
|
330
|
+
*
|
|
331
|
+
* This plugin extracts and processes identity claims from the authentication service.
|
|
332
|
+
*
|
|
333
|
+
* @returns {AuthPluginFactory} A factory function that returns an observable with the processed identity claims.
|
|
334
|
+
*/
|
|
194
335
|
const coreIdentityPlugin = () => {
|
|
195
336
|
const { resolveEmail, resolveUsername, createInitials } = injectAuthConfig();
|
|
196
337
|
return (authService) => {
|
|
@@ -202,6 +343,15 @@ const coreIdentityPlugin = () => {
|
|
|
202
343
|
};
|
|
203
344
|
};
|
|
204
345
|
|
|
346
|
+
/**
|
|
347
|
+
* A plugin factory that generates a user profile URL plugin.
|
|
348
|
+
*
|
|
349
|
+
* This plugin retrieves the user profile URL from the authentication configuration.
|
|
350
|
+
* If the user profile URL is not specified in the configuration, it falls back to
|
|
351
|
+
* using the default URL for the current environment from `ODX_AUTH_USER_PROFILE_HOSTS`.
|
|
352
|
+
*
|
|
353
|
+
* @returns A function that returns an observable emitting an object containing the user profile URL.
|
|
354
|
+
*/
|
|
205
355
|
const userProfileUrlPlugin = () => {
|
|
206
356
|
const { environment, userProfileUrl } = injectAuthConfig();
|
|
207
357
|
return () => {
|
|
@@ -239,6 +389,11 @@ const ODX_AUTH_PLUGINS = new InjectionToken('@odx/auth::Plugins', {
|
|
|
239
389
|
return [...corePlugins, ...plugins].map((pluginFactory) => pluginFactory());
|
|
240
390
|
},
|
|
241
391
|
});
|
|
392
|
+
/**
|
|
393
|
+
* Provides a logger for the authentication module.
|
|
394
|
+
*
|
|
395
|
+
* @returns {Provider} - The provider for the logger.
|
|
396
|
+
*/
|
|
242
397
|
function provideAuthLogger() {
|
|
243
398
|
return {
|
|
244
399
|
provide: ENVIRONMENT_INITIALIZER,
|
|
@@ -251,11 +406,19 @@ function provideAuthLogger() {
|
|
|
251
406
|
multi: true,
|
|
252
407
|
};
|
|
253
408
|
}
|
|
409
|
+
/**
|
|
410
|
+
* Initializes the authentication error handlers.
|
|
411
|
+
*/
|
|
254
412
|
function initializeAuthErrorHandlers() {
|
|
255
413
|
const authService = inject(AuthService);
|
|
256
414
|
const handler = handleAuthError(inject(ODX_AUTH_ERROR_HANDLERS));
|
|
257
415
|
authService.errors$.pipe(tap((error) => handler(error))).subscribe();
|
|
258
416
|
}
|
|
417
|
+
/**
|
|
418
|
+
* Initializes the authentication configuration.
|
|
419
|
+
*
|
|
420
|
+
* @returns {() => Promise<void>} - A function that returns a promise resolving when the configuration is initialized.
|
|
421
|
+
*/
|
|
259
422
|
function initalizeAuthConfig() {
|
|
260
423
|
const { clientId, scopes, redirectPath, environment, postLogoutRedirectUrl, issuer, timeoutFactor, discoveryUrl, enableLoadingScreen } = injectAuthConfig();
|
|
261
424
|
const authService = inject(AuthService);
|
|
@@ -278,6 +441,27 @@ function initalizeAuthConfig() {
|
|
|
278
441
|
waitForTokenInMsec: 1000,
|
|
279
442
|
});
|
|
280
443
|
}
|
|
444
|
+
/**
|
|
445
|
+
* Provides the authentication configuration and dependencies.
|
|
446
|
+
*
|
|
447
|
+
* @param {ConfigProvider<Partial<AuthConfig>, D>} config - The configuration provider.
|
|
448
|
+
* @returns {EnvironmentProviders} The environment providers for authentication.
|
|
449
|
+
* @template D
|
|
450
|
+
*
|
|
451
|
+
* @example Provide the authentication configuration and dependencies
|
|
452
|
+
* ```ts
|
|
453
|
+
* providers: [
|
|
454
|
+
* provideAuth({
|
|
455
|
+
* useFactory: ({ environment, auth: { clientId, loadUserProfile } }: ApplicationEnvironment) => ({
|
|
456
|
+
* environment,
|
|
457
|
+
* clientId,
|
|
458
|
+
* loadUserProfile,
|
|
459
|
+
* }),
|
|
460
|
+
* deps: [APPLICATION_ENVIRONMENT],
|
|
461
|
+
* }),
|
|
462
|
+
* ],
|
|
463
|
+
* ```
|
|
464
|
+
*/
|
|
281
465
|
function provideAuth(config) {
|
|
282
466
|
return makeEnvironmentProviders([
|
|
283
467
|
provideAuthConfig(config),
|
|
@@ -330,10 +514,10 @@ class AuthPluginManager {
|
|
|
330
514
|
runPlugin(authService, plugin) {
|
|
331
515
|
return plugin(authService).pipe(isNumber(this.authConfig.pluginTimeout) ? timeout(Math.max(0, this.authConfig.pluginTimeout)) : tap(), catchError((error) => this.handlePluginError(error)));
|
|
332
516
|
}
|
|
333
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
334
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
517
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthPluginManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
518
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthPluginManager, providedIn: 'root' }); }
|
|
335
519
|
}
|
|
336
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
520
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthPluginManager, decorators: [{
|
|
337
521
|
type: Injectable,
|
|
338
522
|
args: [{ providedIn: 'root' }]
|
|
339
523
|
}] });
|
|
@@ -345,7 +529,40 @@ const offlineAuthErrorHandler = (error) => {
|
|
|
345
529
|
throw error;
|
|
346
530
|
};
|
|
347
531
|
|
|
532
|
+
/**
|
|
533
|
+
* The `AuthService` class provides authentication functionality for an Angular application.
|
|
534
|
+
* It handles OAuth2/OIDC authentication, token management, and user identity claims.
|
|
535
|
+
*
|
|
536
|
+
* Key responsibilities include:
|
|
537
|
+
* - Initializing authentication with a provided configuration.
|
|
538
|
+
* - Managing tokens (access, refresh, and ID tokens).
|
|
539
|
+
* - Checking and emitting authentication and authorization states.
|
|
540
|
+
* - Handling user login and logout flows.
|
|
541
|
+
* - Supporting silent refresh and offline authentication scenarios.
|
|
542
|
+
* - Integrating authentication plugins via `AuthPluginManager`.
|
|
543
|
+
*
|
|
544
|
+
* @example
|
|
545
|
+
* ```typescript
|
|
546
|
+
* // Injecting the AuthService
|
|
547
|
+
* constructor(private authService: AuthService) {}
|
|
548
|
+
*
|
|
549
|
+
* // Using the AuthService to initialize authentication
|
|
550
|
+
* async ngOnInit() {
|
|
551
|
+
* const config: AuthConfig = { clientId: 'your-client-id', discoveryUrl: 'https://example.com/.well-known/openid-configuration' };
|
|
552
|
+
* await this.authService.initialize(config);
|
|
553
|
+
* }
|
|
554
|
+
* ```
|
|
555
|
+
*/
|
|
348
556
|
class AuthService {
|
|
557
|
+
/**
|
|
558
|
+
* Emits whenever the `access_token` in local storage is updated or cleared.
|
|
559
|
+
* Provides an observable for tracking token updates.
|
|
560
|
+
*
|
|
561
|
+
* @type {Observable<StorageEvent | null>}
|
|
562
|
+
*/
|
|
563
|
+
get accessTokenUpdate$() {
|
|
564
|
+
return this.onAccessTokenUpdate$;
|
|
565
|
+
}
|
|
349
566
|
constructor() {
|
|
350
567
|
this.authConfig = injectAuthConfig();
|
|
351
568
|
this.authPluginManager = inject(AuthPluginManager);
|
|
@@ -357,16 +574,62 @@ class AuthService {
|
|
|
357
574
|
this.onAccessTokenUpdate$ = fromEvent(this.windowRef.nativeWindow, 'storage').pipe(filter(({ key }) => key === 'access_token' || key === null), startWith(null), share());
|
|
358
575
|
this.silentRefreshHandler$ = this.isInitialized$$.pipe(filter(Boolean), switchMap(() => this.windowRef.isOnline$), tap((isOnline) => this.updateSilentRefresh(isOnline)));
|
|
359
576
|
this.onAuthStateChange$ = combineLatest([this.oauthService.events.pipe(startWith(null)), this.windowRef.isOnline$, this.onAccessTokenUpdate$]);
|
|
577
|
+
/**
|
|
578
|
+
* Emits `true` when the service has completed initialization.
|
|
579
|
+
* Emits `false` until the initialization is complete.
|
|
580
|
+
*
|
|
581
|
+
* @type {Observable<boolean>}
|
|
582
|
+
*/
|
|
360
583
|
this.isInitialized$ = this.isInitialized$$.pipe(filter(Boolean), distinctUntilChanged());
|
|
584
|
+
/**
|
|
585
|
+
* Emits `true` when the user is being redirected to the login page.
|
|
586
|
+
* Emits `false` when there is no redirection in progress.
|
|
587
|
+
*
|
|
588
|
+
* @type {Observable<boolean>}
|
|
589
|
+
*/
|
|
361
590
|
this.isRedirecting$ = this.isRedirecting$$.pipe(distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }));
|
|
591
|
+
/**
|
|
592
|
+
* Emits `true` when the application is in a loading state (e.g., during redirection or plugin initialization).
|
|
593
|
+
* Emits `false` when there is no ongoing loading activity.
|
|
594
|
+
*
|
|
595
|
+
* @type {Observable<boolean>}
|
|
596
|
+
*/
|
|
362
597
|
this.isLoading$ = merge(this.isRedirecting$, this.authPluginManager.pluginsLoading$).pipe(distinctUntilChanged());
|
|
598
|
+
/**
|
|
599
|
+
* Emits `true` when the user is authenticated.
|
|
600
|
+
* Emits `false` when the user is not authenticated.
|
|
601
|
+
*
|
|
602
|
+
* @type {Observable<boolean>}
|
|
603
|
+
*/
|
|
363
604
|
this.isAuthenticated$ = this.isInitialized$.pipe(switchMap(() => this.authPluginManager.pluginsReady$), switchMap(() => this.onAuthStateChange$), map(() => this.isAuthenticated()), distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }));
|
|
605
|
+
/**
|
|
606
|
+
* Emits the identity claims of the authenticated user.
|
|
607
|
+
* If the user is not authenticated, emits `null`.
|
|
608
|
+
*
|
|
609
|
+
* @type {Observable<OdxAuth.IdentityClaims | null>}
|
|
610
|
+
*/
|
|
364
611
|
this.identityClaims$ = this.isAuthenticated$.pipe(map(() => this.getIdentityClaims()), shareReplay({ bufferSize: 1, refCount: true }));
|
|
612
|
+
/**
|
|
613
|
+
* Emits OAuth error events.
|
|
614
|
+
*
|
|
615
|
+
* @type {Observable<OAuthErrorEvent>}
|
|
616
|
+
*/
|
|
365
617
|
this.errors$ = this.oauthService.events.pipe(filter((event) => event instanceof OAuthErrorEvent), share());
|
|
618
|
+
/**
|
|
619
|
+
* Emits events when an OAuth token is successfully received.
|
|
620
|
+
*
|
|
621
|
+
* @type {Observable<Event>}
|
|
622
|
+
*/
|
|
366
623
|
this.onTokenReceived$ = this.oauthService.events.pipe(filter((event) => event.type === 'token_received'), share());
|
|
367
624
|
this.runPlugins();
|
|
368
625
|
this.silentRefreshHandler$.subscribe();
|
|
369
626
|
}
|
|
627
|
+
/**
|
|
628
|
+
* Initializes the authentication service with the provided configuration.
|
|
629
|
+
*
|
|
630
|
+
* @param {AuthConfig} config - The authentication configuration object.
|
|
631
|
+
* @returns {Promise<void>} Resolves when initialization is complete.
|
|
632
|
+
*/
|
|
370
633
|
async initialize(config) {
|
|
371
634
|
this.assertAudience(config.clientId);
|
|
372
635
|
this.oauthService.configure({ ...config, openUri: this.redirectToLogin.bind(this) });
|
|
@@ -393,57 +656,136 @@ class AuthService {
|
|
|
393
656
|
await this.tryLoadUserProfile();
|
|
394
657
|
await this.routeToRequestedUrl();
|
|
395
658
|
}
|
|
659
|
+
/**
|
|
660
|
+
* Runs all authentication plugins registered in the `AuthPluginManager`.
|
|
661
|
+
*/
|
|
396
662
|
runPlugins() {
|
|
397
663
|
this.authPluginManager.runPlugins(this).subscribe();
|
|
398
664
|
}
|
|
665
|
+
/**
|
|
666
|
+
* Returns the issuer URL for the OAuth server.
|
|
667
|
+
*
|
|
668
|
+
* @returns {URL} The issuer URL.
|
|
669
|
+
*/
|
|
399
670
|
getIssuer() {
|
|
400
671
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
401
672
|
return new URL(this.oauthService.issuer);
|
|
402
673
|
}
|
|
674
|
+
/**
|
|
675
|
+
* Initiates the login flow for the user. Redirects to the login page.
|
|
676
|
+
*
|
|
677
|
+
* @param {string} [url] - The URL to redirect back to after login.
|
|
678
|
+
*/
|
|
403
679
|
signIn(url) {
|
|
404
680
|
this.oauthService.initLoginFlow(url);
|
|
405
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Logs the user out and clears their tokens.
|
|
684
|
+
*
|
|
685
|
+
* @param {boolean} [noRedirect] - If `true`, no redirection occurs after logout.
|
|
686
|
+
*/
|
|
406
687
|
signOut(noRedirect) {
|
|
407
688
|
this.oauthService.logOut(noRedirect || !this.getAccessToken());
|
|
408
689
|
}
|
|
690
|
+
/**
|
|
691
|
+
* Attempts to refresh the user's tokens.
|
|
692
|
+
*
|
|
693
|
+
* @returns {Promise<TokenResponse>} Resolves with the new token response.
|
|
694
|
+
*/
|
|
409
695
|
async refreshTokens() {
|
|
410
696
|
return this.oauthService.refreshToken();
|
|
411
697
|
}
|
|
698
|
+
/**
|
|
699
|
+
* Retrieves the current access token, if available.
|
|
700
|
+
*
|
|
701
|
+
* @returns {string | null} The access token, or `null` if not available.
|
|
702
|
+
*/
|
|
412
703
|
getAccessToken() {
|
|
413
704
|
return this.oauthService.getAccessToken() ?? null;
|
|
414
705
|
}
|
|
706
|
+
/**
|
|
707
|
+
* Retrieves the current refresh token, if available.
|
|
708
|
+
*
|
|
709
|
+
* @returns {string | null} The refresh token, or `null` if not available.
|
|
710
|
+
*/
|
|
415
711
|
getRefreshToken() {
|
|
416
712
|
return this.oauthService.getRefreshToken() ?? null;
|
|
417
713
|
}
|
|
714
|
+
/**
|
|
715
|
+
* Retrieves the current ID token, if available.
|
|
716
|
+
*
|
|
717
|
+
* @returns {string | null} The ID token, or `null` if not available.
|
|
718
|
+
*/
|
|
418
719
|
getIdToken() {
|
|
419
720
|
return this.oauthService.getIdToken() ?? null;
|
|
420
721
|
}
|
|
722
|
+
/**
|
|
723
|
+
* Retrieves the identity claims of the authenticated user.
|
|
724
|
+
*
|
|
725
|
+
* @returns {OdxAuth.IdentityClaims | null} The identity claims, or `null` if not available.
|
|
726
|
+
*/
|
|
421
727
|
getIdentityClaims() {
|
|
422
728
|
if (!this.getIdToken())
|
|
423
729
|
return null;
|
|
424
730
|
return deepmerge(this.oauthService.getIdentityClaims(), this.authPluginManager.getResult());
|
|
425
731
|
}
|
|
732
|
+
/**
|
|
733
|
+
* Retrieves the raw identity claims of the authenticated user.
|
|
734
|
+
*
|
|
735
|
+
* @returns {OdxAuth.RawIdentityClaims | null} The raw identity claims, or `null` if not available.
|
|
736
|
+
*/
|
|
426
737
|
getRawIdentityClaims() {
|
|
427
738
|
if (!this.getIdToken())
|
|
428
739
|
return null;
|
|
429
740
|
return this.oauthService.getIdentityClaims();
|
|
430
741
|
}
|
|
742
|
+
/**
|
|
743
|
+
* Checks if the user is currently authenticated.
|
|
744
|
+
*
|
|
745
|
+
* @returns {boolean} `true` if authenticated, otherwise `false`.
|
|
746
|
+
*/
|
|
431
747
|
isAuthenticated() {
|
|
432
748
|
if (this.windowRef.isOnline()) {
|
|
433
749
|
return this.oauthService.hasValidAccessToken() && this.oauthService.hasValidIdToken();
|
|
434
750
|
}
|
|
435
751
|
return this.hasValidOfflineToken();
|
|
436
752
|
}
|
|
753
|
+
/**
|
|
754
|
+
* Checks if the user is authorized based on the provided handler.
|
|
755
|
+
*
|
|
756
|
+
* @param {AuthorizedHandler | null} [authorizedHandler] - A handler to determine authorization.
|
|
757
|
+
* @returns {boolean} `true` if authorized, otherwise `false`.
|
|
758
|
+
*/
|
|
437
759
|
isAuthorized(authorizedHandler) {
|
|
438
760
|
const handler = authorizedHandler ?? this.authConfig.defaultAuthorizedHandler;
|
|
439
761
|
return this.isAuthenticated() && (handler?.(this.getIdentityClaims(), this, this.router) ?? true);
|
|
440
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* Emits whether the user is authorized based on the provided handler.
|
|
765
|
+
*
|
|
766
|
+
* @param {AuthorizedHandler | null} [authorizedHandler] - A handler to determine authorization.
|
|
767
|
+
* @returns {Observable<boolean>} An observable emitting the authorization status.
|
|
768
|
+
*/
|
|
441
769
|
isAuthorized$(authorizedHandler) {
|
|
442
770
|
return this.isAuthenticated$.pipe(map(() => this.isAuthorized(authorizedHandler)));
|
|
443
771
|
}
|
|
772
|
+
/**
|
|
773
|
+
* Prepares an HTTP request by adding the access token to its headers.
|
|
774
|
+
*
|
|
775
|
+
* @param {HttpRequest<T> | Request} req - The HTTP request to prepare.
|
|
776
|
+
* @param {boolean} requireSignIn - Whether to require the user to sign in if no token is available.
|
|
777
|
+
* @returns {Observable<R>} An observable emitting the prepared request.
|
|
778
|
+
* @template R, T
|
|
779
|
+
*/
|
|
444
780
|
prepareAuthRequest$(req, requireSignIn = false) {
|
|
445
781
|
return this.waitForAccessToken$(requireSignIn).pipe(map((token) => setHttpAuthHeader(req, token)));
|
|
446
782
|
}
|
|
783
|
+
/**
|
|
784
|
+
* Waits for a valid access token to become available.
|
|
785
|
+
*
|
|
786
|
+
* @param {boolean} requireSignIn - Whether to require the user to sign in if no token is available.
|
|
787
|
+
* @returns {Observable<string | null>} An observable emitting the access token.
|
|
788
|
+
*/
|
|
447
789
|
waitForAccessToken$(requireSignIn) {
|
|
448
790
|
const accessToken$ = of(this.getAccessToken()).pipe(filter((token) => !!token && this.isAuthenticated()));
|
|
449
791
|
const waitForAccessToken$ = this.onTokenReceived$.pipe(timeout(this.authConfig.waitForTokenInMs ?? 0), catchError(async () => this.tryRefreshToken().catch(() => null)));
|
|
@@ -486,14 +828,21 @@ class AuthService {
|
|
|
486
828
|
this.oauthService.stopAutomaticRefresh();
|
|
487
829
|
}
|
|
488
830
|
}
|
|
489
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
490
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
831
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
832
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthService, providedIn: 'root' }); }
|
|
491
833
|
}
|
|
492
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
834
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthService, decorators: [{
|
|
493
835
|
type: Injectable,
|
|
494
836
|
args: [{ providedIn: 'root' }]
|
|
495
837
|
}], ctorParameters: () => [] });
|
|
496
838
|
|
|
839
|
+
/**
|
|
840
|
+
* A function that creates a language loader function for user authentication.
|
|
841
|
+
*
|
|
842
|
+
* @param {LanguageSelector} languageSelector - A function that takes optional identity claims and returns a language string, null, or undefined.
|
|
843
|
+
* Defaults to a function that returns the preferred language from the claims.
|
|
844
|
+
* @returns {LanguageLoaderFn} - A function that retrieves the user's preferred language from the identity claims.
|
|
845
|
+
*/
|
|
497
846
|
function userLanguageLoader(languageSelector = (claims) => claims?.preferredLanguage) {
|
|
498
847
|
return () => {
|
|
499
848
|
return inject(AuthService).identityClaims$.pipe(map(languageSelector), map((value) => (isNonEmptyString(value) ? value : undefined)));
|
|
@@ -512,6 +861,43 @@ const ODX_AUTH_USER_PROFILE_HOSTS = {
|
|
|
512
861
|
stage: 'https://purple-cliff-0e61c5703.3.azurestaticapps.net',
|
|
513
862
|
prod: 'https://id.draeger.com',
|
|
514
863
|
};
|
|
864
|
+
/**
|
|
865
|
+
* Tools for injecting and providing the auth configuration with default configuration for the authentication.
|
|
866
|
+
*
|
|
867
|
+
* @example
|
|
868
|
+
* // Providing custom authentication configuration.
|
|
869
|
+
* ```ts
|
|
870
|
+
* import { createInitials, resolveEmail, resolveUsername } from './helpers';
|
|
871
|
+
*
|
|
872
|
+
* providers: [provideAuthConfig({
|
|
873
|
+
* environment: 'dev',
|
|
874
|
+
* redirectPath: 'login/callback',
|
|
875
|
+
* allowedUrls: [],
|
|
876
|
+
* timeoutFactor: 0.75,
|
|
877
|
+
* maxOfflineTime: 60 * 60, // 1 hour
|
|
878
|
+
* loadUserProfile: false,
|
|
879
|
+
* errorHandler: (error) => {
|
|
880
|
+
* throw error;
|
|
881
|
+
* },
|
|
882
|
+
* createInitials,
|
|
883
|
+
* resolveEmail,
|
|
884
|
+
* resolveUsername,
|
|
885
|
+
* plugins: [],
|
|
886
|
+
* defaultAuthorizedHandler: null,
|
|
887
|
+
* enableLoadingScreen: true,
|
|
888
|
+
* loadingScreenMessage: 'Loading...',
|
|
889
|
+
* waitForTokenInMs: 500,
|
|
890
|
+
*
|
|
891
|
+
* })],
|
|
892
|
+
*
|
|
893
|
+
* // Injecting the datepicker configuration.
|
|
894
|
+
* ```ts
|
|
895
|
+
* @Component({})
|
|
896
|
+
* export class MyComponent {
|
|
897
|
+
* constructor(@Inject(injectAuthConfig()) private readonly authConfig: AuthConfig) {}
|
|
898
|
+
* }
|
|
899
|
+
* ```
|
|
900
|
+
*/
|
|
515
901
|
const { AuthDefaultConfig, AuthConfig, injectAuthConfig, provideAuthConfig } = createConfigTokens('Auth', '@odx/auth', {
|
|
516
902
|
environment: 'prod',
|
|
517
903
|
redirectPath: 'login/callback',
|
|
@@ -545,6 +931,12 @@ var translations = {
|
|
|
545
931
|
},
|
|
546
932
|
};
|
|
547
933
|
|
|
934
|
+
/**
|
|
935
|
+
* An abstract directive that integrates with the `LoadingSpinnerDirective` and `AuthService` to manage loading states based on authentication redirection.
|
|
936
|
+
*
|
|
937
|
+
* This directive automatically sets the `autoColor` property of the `LoadingSpinnerDirective` to `true` and subscribes to the `isRedirecting$` observable from the `AuthService`.
|
|
938
|
+
* When `isRedirecting$` emits a value, it updates the `isLoading` property of the `LoadingSpinnerDirective`.
|
|
939
|
+
*/
|
|
548
940
|
class AuthActionDirective {
|
|
549
941
|
constructor() {
|
|
550
942
|
this.takeUntilDestroyed = untilDestroyed();
|
|
@@ -557,16 +949,35 @@ class AuthActionDirective {
|
|
|
557
949
|
this.loadingSpinnerDirective.isLoading = isRedirecting;
|
|
558
950
|
});
|
|
559
951
|
}
|
|
560
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
561
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
952
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthActionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
953
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.12", type: AuthActionDirective, ngImport: i0 }); }
|
|
562
954
|
}
|
|
563
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
955
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthActionDirective, decorators: [{
|
|
564
956
|
type: Directive
|
|
565
957
|
}] });
|
|
566
958
|
|
|
959
|
+
/**
|
|
960
|
+
* A directive that handles the sign-in action for a button element.
|
|
961
|
+
*
|
|
962
|
+
* This directive extends the `AuthActionDirective` and uses the `LoadingSpinnerDirective`
|
|
963
|
+
* to show a loading spinner during the sign-in process.
|
|
964
|
+
*
|
|
965
|
+
* @see {AuthActionDirective}
|
|
966
|
+
* @see {LoadingSpinnerDirective}
|
|
967
|
+
*
|
|
968
|
+
* @example
|
|
969
|
+
* ```html
|
|
970
|
+
* <button odxButton odxAuthSignIn (odxAuthSignIn)="onSignIn()">Sign In</button>
|
|
971
|
+
* ```
|
|
972
|
+
*/
|
|
567
973
|
class SignInDirective extends AuthActionDirective {
|
|
568
974
|
constructor() {
|
|
569
975
|
super(...arguments);
|
|
976
|
+
/**
|
|
977
|
+
* Emits an event after the sign-in action is completed.
|
|
978
|
+
*
|
|
979
|
+
* @type {EventEmitter<void>}
|
|
980
|
+
*/
|
|
570
981
|
// eslint-disable-next-line @angular-eslint/no-output-rename
|
|
571
982
|
this.afterSignIn = new EventEmitter();
|
|
572
983
|
}
|
|
@@ -574,10 +985,10 @@ class SignInDirective extends AuthActionDirective {
|
|
|
574
985
|
this.authService.signIn();
|
|
575
986
|
this.afterSignIn.next();
|
|
576
987
|
}
|
|
577
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
578
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
988
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SignInDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
989
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.12", type: SignInDirective, isStandalone: true, selector: "[odxButton][odxAuthSignIn]", outputs: { afterSignIn: "odxAuthSignIn" }, host: { listeners: { "click": "handleClick()" } }, usesInheritance: true, hostDirectives: [{ directive: i1$1.LoadingSpinnerDirective }], ngImport: i0 }); }
|
|
579
990
|
}
|
|
580
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
991
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SignInDirective, decorators: [{
|
|
581
992
|
type: Directive,
|
|
582
993
|
args: [{
|
|
583
994
|
standalone: true,
|
|
@@ -592,9 +1003,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
592
1003
|
args: ['click']
|
|
593
1004
|
}] } });
|
|
594
1005
|
|
|
1006
|
+
/**
|
|
1007
|
+
* A directive that handles the sign-out action for a button element.
|
|
1008
|
+
*
|
|
1009
|
+
* This directive extends the `AuthActionDirective` and uses the `LoadingSpinnerDirective`
|
|
1010
|
+
* to show a loading spinner during the sign-out process.
|
|
1011
|
+
*
|
|
1012
|
+
* @see {AuthActionDirective}
|
|
1013
|
+
* @see {LoadingSpinnerDirective}
|
|
1014
|
+
*
|
|
1015
|
+
* @example
|
|
1016
|
+
* ```html
|
|
1017
|
+
* <button odxButton odxAuthSignOut (odxAuthSignOut)="onSignOut()">Sign Out</button>
|
|
1018
|
+
* ```
|
|
1019
|
+
*/
|
|
595
1020
|
class SignOutDirective extends AuthActionDirective {
|
|
596
1021
|
constructor() {
|
|
597
1022
|
super(...arguments);
|
|
1023
|
+
/**
|
|
1024
|
+
* Emits an event after the sign-out action is completed.
|
|
1025
|
+
*
|
|
1026
|
+
* @type {EventEmitter<void>}
|
|
1027
|
+
*/
|
|
598
1028
|
// eslint-disable-next-line @angular-eslint/no-output-rename
|
|
599
1029
|
this.afterSignOut = new EventEmitter();
|
|
600
1030
|
}
|
|
@@ -602,10 +1032,10 @@ class SignOutDirective extends AuthActionDirective {
|
|
|
602
1032
|
this.authService.signOut();
|
|
603
1033
|
this.afterSignOut.next();
|
|
604
1034
|
}
|
|
605
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
606
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
1035
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SignOutDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1036
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.12", type: SignOutDirective, isStandalone: true, selector: "[odxButton][odxAuthSignOut]", outputs: { afterSignOut: "odxAuthSignOut" }, host: { listeners: { "click": "handleClick()" } }, usesInheritance: true, hostDirectives: [{ directive: i1$1.LoadingSpinnerDirective }], ngImport: i0 }); }
|
|
607
1037
|
}
|
|
608
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1038
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SignOutDirective, decorators: [{
|
|
609
1039
|
type: Directive,
|
|
610
1040
|
args: [{
|
|
611
1041
|
standalone: true,
|
|
@@ -633,12 +1063,17 @@ class AuthComponent {
|
|
|
633
1063
|
idClaims: this.authService.identityClaims$,
|
|
634
1064
|
isAuthenticated: this.authService.isAuthenticated$,
|
|
635
1065
|
});
|
|
1066
|
+
/**
|
|
1067
|
+
* Whether to hide the institution information.
|
|
1068
|
+
*
|
|
1069
|
+
* @type {InputSignal<boolean>}
|
|
1070
|
+
*/
|
|
636
1071
|
this.hideInstitution = input(false);
|
|
637
1072
|
}
|
|
638
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
639
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1073
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1074
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: AuthComponent, isStandalone: true, selector: "odx-auth", inputs: { hideInstitution: { classPropertyName: "hideInstitution", publicName: "hideInstitution", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideTranslations(translations)], ngImport: i0, template: "<odx-action-group>\n @if (vm$ | async; as vm) {\n <ng-container ngProjectAs=\"[odxButton]\">\n @if (vm.isAuthenticated) {\n <button odxButton [odxDropdown]=\"userProfileMenu\" [odxDropdownOptions]=\"dropdownOptions\" data-testid=\"odx-auth-user-profile-button\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\" />\n </button>\n } @else {\n <button class=\"odx-auth-sign-in\" odxButton odxAuthSignIn variant=\"secondary\" data-testid=\"odx-auth-sign-in-button\">\n <odx-icon name=\"user\" alignLeft />\n {{ 'signInButtonText' | odxTranslate | async }}\n </button>\n }\n <ng-template #userProfileMenu>\n @if (!hideInstitution() && vm.idClaims?.institutionName; as institutionName) {\n <odx-area-header class=\"odx-padding-x-12 odx-padding-bottom-8\" size=\"small\">\n <odx-area-header-subtitle class=\"odx-auth-institution-name\">{{ institutionName }}</odx-area-header-subtitle>\n </odx-area-header>\n }\n <odx-area-header class=\"odx-padding-x-12\" size=\"small\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\" ngProjectAs=\"odx-avatar\" />\n {{ vm.idClaims?.username }}\n <odx-area-header-subtitle>\n {{ vm.idClaims?.email }}\n </odx-area-header-subtitle>\n </odx-area-header>\n <ng-content />\n <odx-auth-actions [claims]=\"vm.idClaims\"></odx-auth-actions>\n <div class=\"odx-margin-top-12\" odxLayout=\"flex vertical-center\">\n <odx-logo odxLayout=\"auto\" class=\"odx-margin-left-12 odx-margin-right-auto\"></odx-logo>\n <button odxButton odxAuthSignOut variant=\"ghost\" data-testid=\"odx-auth-sign-out-button\">\n {{ 'signOutButtonText' | odxTranslate | async }}\n <odx-icon name=\"logout\" alignRight />\n </button>\n </div>\n </ng-template>\n <ng-template #userAvatar>\n <odx-avatar class=\"odx-auth-user-avatar\">\n {{ vm.idClaims?.initials ?? '' }}\n </odx-avatar>\n </ng-template>\n </ng-container>\n }\n</odx-action-group>\n", styles: [".odx-auth-user-profile .odx-dropdown__inner>.odx-area-header{max-width:max(360px,25vw);min-width:296px}.odx-auth-actions{display:block;margin-top:calc(var(--odx-vertical-rythm-base-size) * .5);margin-bottom:calc(var(--odx-vertical-rythm-base-size) * .5);margin-right:calc(var(--odx-vertical-rythm-base-size) * .25);margin-left:calc(var(--odx-vertical-rythm-base-size) * .25)}\n"], dependencies: [{ kind: "ngmodule", type: AreaHeaderModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "component", type: i2$1.AreaHeaderComponent, selector: "odx-area-header", inputs: ["size"] }, { kind: "directive", type: i2$1.AreaHeaderSubtitleDirective, selector: "odx-area-header-subtitle" }, { kind: "component", type: i3$1.AvatarComponent, selector: "odx-avatar", inputs: ["size", "variant"] }, { kind: "component", type: i4.ActionGroupComponent, selector: "odx-action-group", inputs: ["reverse"] }, { kind: "component", type: i5.ButtonComponent, selector: "button[odxButton], a[odxButton]", inputs: ["variant", "size"] }, { kind: "component", type: i3.IconComponent, selector: "odx-icon", inputs: ["inline", "size", "name", "iconSet", "identifier"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "directive", type: i7.DropdownDirective, selector: "[odxDropdown]", inputs: ["odxDropdown", "odxDropdownDisabled", "odxDropdownShowLoader", "odxDropdownClickOutsideActive", "odxDropdownOptions", "odxDropdownReferenceElement", "odxDropdownTriggerElement", "odxDropdownHost", "odxDropdownOpenTrigger", "odxDropdownCloseTrigger"], outputs: ["odxDropdownBeforeOpen", "odxDropdownAfterOpen", "odxDropdownBeforeClose", "odxDropdownAfterClose"], exportAs: ["odxDropdown"] }, { kind: "ngmodule", type: HeaderModule }, { kind: "directive", type: LogoDirective, selector: "odx-logo", inputs: ["size", "variant"] }, { kind: "directive", type: SignInDirective, selector: "[odxButton][odxAuthSignIn]", outputs: ["odxAuthSignIn"] }, { kind: "directive", type: SignOutDirective, selector: "[odxButton][odxAuthSignOut]", outputs: ["odxAuthSignOut"] }, { kind: "ngmodule", type: LoadingSpinnerModule }, { kind: "component", type: AuthActionsComponent, selector: "odx-auth-actions", inputs: ["claims"] }, { kind: "pipe", type: TranslatePipe, name: "odxTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
640
1075
|
}
|
|
641
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1076
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthComponent, decorators: [{
|
|
642
1077
|
type: Component,
|
|
643
1078
|
args: [{ standalone: true, selector: 'odx-auth', imports: [
|
|
644
1079
|
AreaHeaderModule,
|
|
@@ -659,8 +1094,18 @@ class AuthDirective {
|
|
|
659
1094
|
this.authService = inject(AuthService);
|
|
660
1095
|
this.ngIfDirective = inject(NgIf, { host: true });
|
|
661
1096
|
this.takeUntilDestroyed = untilDestroyed();
|
|
1097
|
+
/**
|
|
1098
|
+
* The authorization handler or a string representing the handler.
|
|
1099
|
+
*
|
|
1100
|
+
* @type {AuthorizedHandler | null | string}
|
|
1101
|
+
*/
|
|
662
1102
|
this.authorizationHandler = null;
|
|
663
1103
|
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Sets the template to be displayed when the authorization check fails.
|
|
1106
|
+
*
|
|
1107
|
+
* @param {TemplateRef<NgIfContext<unknown>>} value - The template reference.
|
|
1108
|
+
*/
|
|
664
1109
|
// eslint-disable-next-line @angular-eslint/no-input-rename
|
|
665
1110
|
set elseTemplate(value) {
|
|
666
1111
|
this.ngIfDirective.ngIfElse = value;
|
|
@@ -671,10 +1116,10 @@ class AuthDirective {
|
|
|
671
1116
|
this.ngIfDirective.ngIf = this.authService.isAuthorized(handler);
|
|
672
1117
|
});
|
|
673
1118
|
}
|
|
674
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
675
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
1119
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1120
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.12", type: AuthDirective, isStandalone: true, selector: "ng-template[odxAuth]", inputs: { authorizationHandler: ["odxAuth", "authorizationHandler"], elseTemplate: ["odxAuthElse", "elseTemplate"] }, hostDirectives: [{ directive: i1.NgIf }], ngImport: i0 }); }
|
|
676
1121
|
}
|
|
677
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1122
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthDirective, decorators: [{
|
|
678
1123
|
type: Directive,
|
|
679
1124
|
args: [{
|
|
680
1125
|
standalone: true,
|
|
@@ -689,6 +1134,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
689
1134
|
args: ['odxAuthElse']
|
|
690
1135
|
}] } });
|
|
691
1136
|
|
|
1137
|
+
/**
|
|
1138
|
+
* Guard function to protect routes from unauthorized access.
|
|
1139
|
+
*
|
|
1140
|
+
* @param {AuthorizedHandler} [authorizedHandler] - Optional handler to check if the user is authorized.
|
|
1141
|
+
* @param {string | any[]} [redirectTo] - Optional URL or route to redirect unauthorized users to. Can be a string or an array of strings.
|
|
1142
|
+
* @param {boolean} [isExternal=false] - Optional flag to indicate if the redirection should be external. Defaults to false.
|
|
1143
|
+
* @returns {CanActivateFn} A function that implements the CanActivateFn interface.
|
|
1144
|
+
*/
|
|
692
1145
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
693
1146
|
function authGuard(authorizedHandler, redirectTo, isExternal = false) {
|
|
694
1147
|
return (_, state) => {
|
|
@@ -721,11 +1174,11 @@ function authGuard(authorizedHandler, redirectTo, isExternal = false) {
|
|
|
721
1174
|
|
|
722
1175
|
const modules = [AuthComponent, AuthDirective, SignInDirective, SignOutDirective];
|
|
723
1176
|
class AuthModule {
|
|
724
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
725
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
726
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
1177
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1178
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.12", ngImport: i0, type: AuthModule, imports: [AuthComponent, AuthDirective, SignInDirective, SignOutDirective], exports: [AuthComponent, AuthDirective, SignInDirective, SignOutDirective] }); }
|
|
1179
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthModule, imports: [AuthComponent] }); }
|
|
727
1180
|
}
|
|
728
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1181
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: AuthModule, decorators: [{
|
|
729
1182
|
type: NgModule,
|
|
730
1183
|
args: [{
|
|
731
1184
|
imports: [...modules],
|
|
@@ -733,6 +1186,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
733
1186
|
}]
|
|
734
1187
|
}] });
|
|
735
1188
|
|
|
1189
|
+
/**
|
|
1190
|
+
* Guard function to prevent unauthorized access to routes.
|
|
1191
|
+
*
|
|
1192
|
+
* @param {AuthorizedHandler} authorizedHandler - Optional handler to check if the user is authorized.
|
|
1193
|
+
* @param {any[] | string} redirectTo - Optional URL or route to redirect unauthorized users to. Can be a string or an array of strings.
|
|
1194
|
+
* @param {boolean} isExternal - Optional flag to indicate if the redirection should be external. Defaults to false.
|
|
1195
|
+
* @returns {CanActivateFn} - A function that implements the CanActivateFn interface.
|
|
1196
|
+
*/
|
|
736
1197
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
737
1198
|
function unauthGuard(authorizedHandler, redirectTo, isExternal = false) {
|
|
738
1199
|
return (_) => {
|