@odx/auth 1.0.0-alpha.1 → 1.0.0-rc.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.
Files changed (48) hide show
  1. package/esm2020/index.mjs +6 -3
  2. package/esm2020/lib/auth-error-handler.mjs +20 -0
  3. package/esm2020/lib/auth.component.mjs +13 -21
  4. package/esm2020/lib/auth.config.mjs +11 -3
  5. package/esm2020/lib/auth.directive.mjs +41 -0
  6. package/esm2020/lib/auth.guard.mjs +18 -0
  7. package/esm2020/lib/auth.module.mjs +10 -12
  8. package/esm2020/lib/auth.providers.mjs +53 -42
  9. package/esm2020/lib/auth.service.mjs +87 -21
  10. package/esm2020/lib/auth.typings.mjs +2 -0
  11. package/esm2020/lib/directives/sign-in.directive.mjs +6 -6
  12. package/esm2020/lib/directives/sign-out.directive.mjs +6 -6
  13. package/esm2020/lib/helpers/create-inititals.mjs +12 -0
  14. package/esm2020/lib/helpers/index.mjs +3 -3
  15. package/esm2020/lib/helpers/parse-identity-claims.mjs +10 -0
  16. package/esm2020/lib/models/authorized-handler.mjs +2 -0
  17. package/esm2020/lib/models/index.mjs +2 -2
  18. package/fesm2015/odx-auth.mjs +255 -134
  19. package/fesm2015/odx-auth.mjs.map +1 -1
  20. package/fesm2020/odx-auth.mjs +252 -135
  21. package/fesm2020/odx-auth.mjs.map +1 -1
  22. package/index.d.ts +5 -2
  23. package/lib/auth-error-handler.d.ts +12 -0
  24. package/lib/auth.component.d.ts +2 -3
  25. package/lib/auth.config.d.ts +11 -6
  26. package/lib/auth.directive.d.ts +15 -0
  27. package/lib/auth.guard.d.ts +3 -0
  28. package/lib/auth.module.d.ts +4 -4
  29. package/lib/auth.providers.d.ts +9 -6
  30. package/lib/auth.service.d.ts +27 -11
  31. package/lib/auth.typings.d.ts +19 -0
  32. package/lib/directives/sign-in.directive.d.ts +3 -3
  33. package/lib/directives/sign-out.directive.d.ts +3 -3
  34. package/lib/helpers/create-inititals.d.ts +1 -0
  35. package/lib/helpers/index.d.ts +2 -2
  36. package/lib/helpers/parse-identity-claims.d.ts +1 -0
  37. package/lib/models/auth-environment.d.ts +1 -1
  38. package/lib/models/authorized-handler.d.ts +4 -0
  39. package/lib/models/index.d.ts +1 -1
  40. package/package.json +3 -4
  41. package/esm2020/lib/auth.interceptor.mjs +0 -25
  42. package/esm2020/lib/helpers/get-user-initials.mjs +0 -12
  43. package/esm2020/lib/helpers/resolve-issuer.mjs +0 -13
  44. package/esm2020/lib/models/user.mjs +0 -2
  45. package/lib/auth.interceptor.d.ts +0 -11
  46. package/lib/helpers/get-user-initials.d.ts +0 -2
  47. package/lib/helpers/resolve-issuer.d.ts +0 -2
  48. package/lib/models/user.d.ts +0 -4
@@ -1,10 +1,6 @@
1
- import { OKTA_AUTH, OktaAuthStateService, OktaCallbackComponent, OKTA_CONFIG, OktaAuthModule } from '@okta/okta-angular';
2
- export { OktaAuthGuard as AuthGuard } from '@okta/okta-angular';
3
- import { __decorate, __metadata } from 'tslib';
4
1
  import * as i0 from '@angular/core';
5
- import { inject, Injectable, EventEmitter, Directive, Output, HostListener, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, APP_INITIALIZER, NgModule } from '@angular/core';
6
- import * as i2 from '@odx/angular';
7
- import { CoreModule, WindowRef } from '@odx/angular';
2
+ import { Injectable, inject, EventEmitter, Directive, Output, HostListener, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, makeEnvironmentProviders, APP_INITIALIZER, NgModule } from '@angular/core';
3
+ import { WindowRef, CoreModule } from '@odx/angular';
8
4
  import * as i3 from '@odx/angular/components/area-header';
9
5
  import { AreaHeaderModule } from '@odx/angular/components/area-header';
10
6
  import * as i8 from '@odx/angular/components/dropdown';
@@ -12,58 +8,167 @@ import { DropdownModule } from '@odx/angular/components/dropdown';
12
8
  import * as i9 from '@odx/angular/components/header';
13
9
  import { HeaderModule } from '@odx/angular/components/header';
14
10
  import { LogoDirective } from '@odx/angular/components/logo';
15
- import { createModuleConfigTokens, Pure, buildUrl, provideModuleConfig } from '@odx/angular/utils';
16
- import { map, shareReplay } from 'rxjs';
11
+ import { createModuleConfigTokens, Position, untilDestroyed, isString, buildUrl, provideModuleConfig } from '@odx/angular/utils';
12
+ import { Router } from '@angular/router';
13
+ import { OAuthService, OAuthErrorEvent, provideOAuthClient, OAuthModuleConfig, OAuthStorage } from 'angular-oauth2-oidc';
14
+ import { BehaviorSubject, fromEvent, filter, startWith, share, combineLatest, switchMap, map, distinctUntilChanged, shareReplay, merge, tap, take } from 'rxjs';
17
15
  import * as i1 from '@odx/angular/components/loading-spinner';
18
16
  import { LoadingSpinnerDirective } from '@odx/angular/components/loading-spinner';
19
17
  import * as i1$1 from '@angular/common';
18
+ import { NgIf } from '@angular/common';
19
+ import * as i2 from '@ngrx/component';
20
20
  import * as i4 from '@odx/angular/components/avatar';
21
21
  import * as i5 from '@odx/angular/components/action-group';
22
22
  import * as i6 from '@odx/angular/components/button';
23
23
  import * as i7 from '@odx/angular/components/icon';
24
- import { HTTP_INTERCEPTORS } from '@angular/common/http';
25
- import { Router } from '@angular/router';
26
- import { OktaAuth } from '@okta/okta-auth-js';
27
24
 
28
- const DEFAULT_AUTH_SCOPES = ['openid', 'profile'];
25
+ class AuthErrorHandler {
26
+ }
27
+ AuthErrorHandler.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthErrorHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
28
+ AuthErrorHandler.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthErrorHandler });
29
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthErrorHandler, decorators: [{
30
+ type: Injectable
31
+ }] });
32
+ class NoopAuthErrorHandler extends AuthErrorHandler {
33
+ handleError(error) {
34
+ throw error;
35
+ }
36
+ }
37
+ NoopAuthErrorHandler.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: NoopAuthErrorHandler, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
38
+ NoopAuthErrorHandler.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: NoopAuthErrorHandler });
39
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: NoopAuthErrorHandler, decorators: [{
40
+ type: Injectable
41
+ }] });
42
+
43
+ const DEFAULT_AUTH_SCOPES = ['openid', 'profile', 'email', 'offline_access'];
44
+ const DEFAULT_ISSUERS = {
45
+ dev: 'https://dev.login.draeger.com/oauth2/default',
46
+ stage: 'https://test.login.draeger.com/oauth2/default',
47
+ prod: 'https://login.draeger.com/oauth2/default',
48
+ };
29
49
  const { AuthDefaultModuleConfig, AuthModuleConfig, injectAuthModuleConfig } = createModuleConfigTokens('Auth', '@odx/auth', {
30
50
  environment: 'prod',
31
51
  redirectPath: 'login/callback',
32
- disallowedOrigins: [],
52
+ allowedUrls: [],
53
+ timeoutFactor: 0.75,
54
+ maxOfflineTime: 24 * 60 * 60,
55
+ loadUserProfile: false,
33
56
  });
34
57
 
58
+ function createInititals(value) {
59
+ if (!value)
60
+ return '';
61
+ const parts = value.trim().split(' ');
62
+ return parts.reduce((initials, curr, index) => {
63
+ if (index === 0 || index === parts.length - 1) {
64
+ initials = `${initials}${curr.charAt(0).toUpperCase()}`;
65
+ }
66
+ return initials;
67
+ }, '');
68
+ }
69
+
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ function parseIdentityClaims(identityClaims) {
72
+ return {
73
+ ...identityClaims,
74
+ email: identityClaims?.email ?? identityClaims.email_address ?? identityClaims.emails?.[0],
75
+ initials: createInititals(identityClaims.name),
76
+ };
77
+ }
78
+
35
79
  class AuthService {
36
80
  constructor() {
37
- this.auth = inject(OKTA_AUTH);
38
- this.authState = inject(OktaAuthStateService);
39
- this.isAuthenticated$ = this.authState.authState$.pipe(map(({ isAuthenticated }) => !!isAuthenticated), shareReplay({ refCount: true }));
40
- this.user$ = this.authState.authState$.pipe(map(({ idToken }) => idToken?.claims ?? null), shareReplay({ refCount: true }));
81
+ this.authConfig = injectAuthModuleConfig();
82
+ this.errorHandler = inject(AuthErrorHandler);
83
+ this.oauthService = inject(OAuthService);
84
+ this.router = inject(Router);
85
+ this.windowRef = inject(WindowRef);
86
+ this.isInitialized$$ = new BehaviorSubject(false);
87
+ this.onAccessTokenUpdate$ = fromEvent(this.windowRef.nativeWindow, 'storage').pipe(filter(({ key }) => key === 'access_token' || key === null), startWith(null), share());
88
+ this.onAuthStateChange$ = combineLatest([this.oauthService.events.pipe(startWith(null)), this.windowRef.isOnline$, this.onAccessTokenUpdate$]);
89
+ this.isAuthenticated$ = this.isInitialized$$.pipe(filter(Boolean), switchMap(() => this.onAuthStateChange$), map(() => this.isAuthenticated()), distinctUntilChanged(), shareReplay({ refCount: true }));
90
+ this.identityClaims$ = this.isAuthenticated$.pipe(map(() => this.getIdentityClaims()), shareReplay({ refCount: true }));
91
+ this.errors$ = this.oauthService.events.pipe(filter((event) => event instanceof OAuthErrorEvent), share());
92
+ this.subscription = merge(this.errors$.pipe(tap((error) => {
93
+ this.errorHandler.handleError(error);
94
+ })), this.windowRef.isOnline$.pipe(tap((isOnline) => {
95
+ if (isOnline) {
96
+ this.oauthService.setupAutomaticSilentRefresh();
97
+ }
98
+ else {
99
+ this.oauthService.stopAutomaticRefresh();
100
+ }
101
+ }))).subscribe();
41
102
  }
42
- async signIn() {
43
- await this.auth.signInWithRedirect();
103
+ ngOnDestroy() {
104
+ this.subscription.unsubscribe();
44
105
  }
45
- async signOut() {
46
- await this.auth.signOut();
106
+ async initialize(config) {
107
+ this.oauthService.configure(config);
108
+ try {
109
+ await this.oauthService.loadDiscoveryDocument(this.authConfig.discoveryUrl);
110
+ await this.oauthService.tryLoginCodeFlow();
111
+ if (this.getRefreshToken() && !this.isAuthenticated()) {
112
+ await this.oauthService.refreshToken();
113
+ }
114
+ this.isInitialized$$.next(true);
115
+ if (this.authConfig.loadUserProfile && this.oauthService.hasValidAccessToken()) {
116
+ await this.loadUserProfile();
117
+ }
118
+ }
119
+ catch {
120
+ // ignore errors
121
+ }
122
+ if (this.oauthService.hasValidAccessToken()) {
123
+ await this.routeToRequestedUrl();
124
+ }
125
+ }
126
+ signIn(url) {
127
+ this.oauthService.initCodeFlow(url);
128
+ }
129
+ signOut() {
130
+ this.oauthService.logOut(!this.getAccessToken());
131
+ }
132
+ async loadUserProfile() {
133
+ await this.oauthService.loadUserProfile();
47
134
  }
48
135
  getAccessToken() {
49
- return this.auth.getAccessToken() ?? null;
136
+ return this.oauthService.getAccessToken() ?? null;
50
137
  }
51
138
  getRefreshToken() {
52
- return this.auth.getRefreshToken() ?? null;
139
+ return this.oauthService.getRefreshToken() ?? null;
140
+ }
141
+ getIdToken() {
142
+ return this.oauthService.getIdToken() ?? null;
143
+ }
144
+ getIdentityClaims() {
145
+ return this.getIdToken() ? parseIdentityClaims(this.oauthService.getIdentityClaims()) : null;
146
+ }
147
+ isAuthenticated() {
148
+ if (this.windowRef.isOnline()) {
149
+ return this.oauthService.hasValidAccessToken() && this.oauthService.hasValidIdToken();
150
+ }
151
+ return this.hasValidOfflineToken();
152
+ }
153
+ isAuthorized(authorizedHandler) {
154
+ return this.isAuthenticated() && (authorizedHandler?.(this.getIdentityClaims(), this) ?? true);
53
155
  }
54
- getAuthHeader() {
55
- return { Authorization: `Bearer ${this.getAccessToken()}` };
156
+ async routeToRequestedUrl() {
157
+ if (this.oauthService.state) {
158
+ await this.router.navigateByUrl(decodeURIComponent(this.oauthService.state));
159
+ }
56
160
  }
57
- hasAnyGroups$(groups) {
58
- return this.authState.hasAnyGroups(groups);
161
+ hasValidOfflineToken() {
162
+ const issuedAt = this.getIdentityClaims()?.iat ?? 0;
163
+ return Date.now() - issuedAt * 1000 <= this.authConfig.maxOfflineTime * 1000;
59
164
  }
60
165
  }
61
- AuthService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
62
- AuthService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthService, providedIn: 'root' });
63
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthService, decorators: [{
166
+ AuthService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
167
+ AuthService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthService, providedIn: 'root' });
168
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthService, decorators: [{
64
169
  type: Injectable,
65
170
  args: [{ providedIn: 'root' }]
66
- }] });
171
+ }], ctorParameters: function () { return []; } });
67
172
 
68
173
  class SignInDirective {
69
174
  constructor() {
@@ -72,18 +177,18 @@ class SignInDirective {
72
177
  // eslint-disable-next-line @angular-eslint/no-output-rename
73
178
  this.afterSignIn = new EventEmitter();
74
179
  }
75
- ngOnInit() {
180
+ ngAfterViewInit() {
76
181
  this.loadingSpinnerDirective.autoColor = true;
77
182
  }
78
183
  async signIn() {
79
184
  this.loadingSpinnerDirective.isLoading = true;
80
- await this.authService.signIn();
185
+ this.authService.signIn();
81
186
  this.afterSignIn.emit();
82
187
  }
83
188
  }
84
- SignInDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: SignInDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
85
- SignInDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.0", type: SignInDirective, isStandalone: true, selector: "[odxButton][odxAuthSignIn]", outputs: { afterSignIn: "odxAuthSignIn" }, host: { listeners: { "click": "signIn()" } }, hostDirectives: [{ directive: i1.LoadingSpinnerDirective }], ngImport: i0 });
86
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: SignInDirective, decorators: [{
189
+ SignInDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: SignInDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
190
+ SignInDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.1", type: SignInDirective, isStandalone: true, selector: "[odxButton][odxAuthSignIn]", outputs: { afterSignIn: "odxAuthSignIn" }, host: { listeners: { "click": "signIn()" } }, hostDirectives: [{ directive: i1.LoadingSpinnerDirective }], ngImport: i0 });
191
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: SignInDirective, decorators: [{
87
192
  type: Directive,
88
193
  args: [{
89
194
  standalone: true,
@@ -105,18 +210,18 @@ class SignOutDirective {
105
210
  // eslint-disable-next-line @angular-eslint/no-output-rename
106
211
  this.afterSignOut = new EventEmitter();
107
212
  }
108
- ngOnInit() {
213
+ ngAfterViewInit() {
109
214
  this.loadingSpinnerDirective.autoColor = true;
110
215
  }
111
216
  async signIn() {
112
217
  this.loadingSpinnerDirective.isLoading = true;
113
- await this.authService.signOut();
218
+ this.authService.signOut();
114
219
  this.afterSignOut.emit();
115
220
  }
116
221
  }
117
- SignOutDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: SignOutDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
118
- SignOutDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.0", type: SignOutDirective, isStandalone: true, selector: "[odxButton][odxAuthSignOut]", outputs: { afterSignOut: "odxAuthSignOut" }, host: { listeners: { "click": "signIn()" } }, hostDirectives: [{ directive: i1.LoadingSpinnerDirective }], ngImport: i0 });
119
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: SignOutDirective, decorators: [{
222
+ SignOutDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: SignOutDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
223
+ SignOutDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.1", type: SignOutDirective, isStandalone: true, selector: "[odxButton][odxAuthSignOut]", outputs: { afterSignOut: "odxAuthSignOut" }, host: { listeners: { "click": "signIn()" } }, hostDirectives: [{ directive: i1.LoadingSpinnerDirective }], ngImport: i0 });
224
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: SignOutDirective, decorators: [{
120
225
  type: Directive,
121
226
  args: [{
122
227
  standalone: true,
@@ -131,137 +236,149 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImpor
131
236
  args: ['click']
132
237
  }] } });
133
238
 
134
- function getUserInitials(user) {
135
- if (!user?.name)
136
- return '';
137
- const names = user.name.trim().split(' ');
138
- return names.reduce((initials, curr, index) => {
139
- if (index === 0 || index === names.length - 1) {
140
- initials = `${initials}${curr.charAt(0).toUpperCase()}`;
141
- }
142
- return initials;
143
- }, '');
144
- }
145
-
146
- function resolveIssuer(environment, issuerOverride) {
147
- if (issuerOverride)
148
- return issuerOverride;
149
- switch (environment) {
150
- case 'dev':
151
- return 'https://dev.login.draeger.com/oauth2/default';
152
- case 'stage':
153
- return 'https://test.login.draeger.com/oauth2/default';
154
- default:
155
- return 'https://login.draeger.com/oauth2/default';
156
- }
157
- }
158
-
159
239
  class AuthComponent {
160
240
  constructor() {
161
- this.config = injectAuthModuleConfig();
162
241
  this.authService = inject(AuthService);
242
+ this.dropdownOptions = {
243
+ position: Position.BOTTOM_END,
244
+ enableFallback: false,
245
+ containerClass: 'odx-auth-user-profile',
246
+ };
163
247
  this.signInButtonText = 'Sign in';
164
248
  this.signOutButtonText = 'Sign out';
165
249
  }
166
- getInitials(user) {
167
- return getUserInitials(user);
168
- }
169
250
  }
170
- AuthComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
171
- AuthComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.0", type: AuthComponent, isStandalone: true, selector: "odx-auth", inputs: { signInButtonText: "signInButtonText", signOutButtonText: "signOutButtonText" }, ngImport: i0, template: "<odx-action-group *odxLet=\"authService.user$ | async as user\">\n <ng-template [ngIf]=\"authService.isAuthenticated$ | async\" [ngIfElse]=\"notAuthenticated\">\n <button odxButton odxHeaderAvatar [odxDropdown]=\"userProfileMenu\">\n <odx-avatar>\n {{ getInitials(user) }}\n </odx-avatar>\n </button>\n </ng-template>\n <ng-template #notAuthenticated>\n <button class=\"odx-auth-sign-in\" odxButton odxAuthSignIn variant=\"primary\">\n <odx-icon name=\"user\" alignLeft></odx-icon>\n {{ signInButtonText }}\n </button>\n </ng-template>\n <ng-template #userProfileMenu>\n <odx-area-header class=\"odx-padding-x-12\" size=\"small\">\n <odx-avatar>\n {{ getInitials(user) }}\n </odx-avatar>\n <h2 class=\"odx-title\">{{ user?.name }}</h2>\n <h5 class=\"odx-subtitle\">{{ user?.email_address }}</h5>\n </odx-area-header>\n <ng-content></ng-content>\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\">\n {{ signOutButtonText }}\n <odx-icon name=\"arrow-right\" alignRight></odx-icon>\n </button>\n </div>\n </ng-template>\n</odx-action-group>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "directive", type: i2.LetDirective, selector: "ng-template[odxLet]", inputs: ["odxLet"] }, { kind: "ngmodule", type: AreaHeaderModule }, { kind: "component", type: i3.AreaHeaderComponent, selector: "odx-area-header", inputs: ["size"] }, { kind: "component", type: i4.AvatarComponent, selector: "odx-avatar", inputs: ["size", "variant"] }, { kind: "component", type: i5.ActionGroupComponent, selector: "odx-action-group", inputs: ["reverse"] }, { kind: "component", type: i6.ButtonComponent, selector: "button[odxButton], a[odxButton]", inputs: ["variant", "size"] }, { kind: "component", type: i7.IconComponent, selector: "odx-icon", inputs: ["inline", "size", "name"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "directive", type: i8.DropdownDirective, selector: "[odxDropdown]", inputs: ["odxDropdown", "odxDropdownDisabled", "odxDropdownShowLoader", "odxDropdownOptions", "odxDropdownReferenceElement", "odxDropdownTriggerElement", "odxDropdownHost", "odxDropdownOpenTrigger", "odxDropdownCloseTrigger"], outputs: ["odxDropdownBeforeOpen", "odxDropdownAfterOpen", "odxDropdownBeforeClose", "odxDropdownAfterClose"], exportAs: ["odxDropdown"] }, { kind: "ngmodule", type: HeaderModule }, { kind: "directive", type: i9.HeaderAvatarDirective, selector: "button[odxButton][odxHeaderAvatar]" }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
172
- __decorate([
173
- Pure,
174
- __metadata("design:type", Function),
175
- __metadata("design:paramtypes", [Object]),
176
- __metadata("design:returntype", String)
177
- ], AuthComponent.prototype, "getInitials", null);
178
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthComponent, decorators: [{
251
+ AuthComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
252
+ AuthComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.1", type: AuthComponent, isStandalone: true, selector: "odx-auth", inputs: { signInButtonText: "signInButtonText", signOutButtonText: "signOutButtonText" }, ngImport: i0, template: "<odx-action-group *ngrxLet=\"{ idClaims: authService.identityClaims$, isAuthenticated: authService.isAuthenticated$ } as vm\">\n <ng-template [ngIf]=\"vm.isAuthenticated\" [ngIfElse]=\"notAuthenticated\">\n <button odxButton odxHeaderAvatar [odxDropdown]=\"userProfileMenu\" [odxDropdownOptions]=\"dropdownOptions\" data-testid=\"odx-auth-user-profile-button\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\"></ng-template>\n </button>\n <ng-template #userProfileMenu>\n <odx-area-header class=\"odx-padding-x-12\" size=\"small\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\" ngProjectAs=\"odx-avatar\"></ng-template>\n {{ vm.idClaims?.name }}\n <odx-area-header-subtitle>\n {{ vm.idClaims?.email }}\n </odx-area-header-subtitle>\n </odx-area-header>\n <ng-content></ng-content>\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 }}\n <odx-icon name=\"arrow-right\" alignRight></odx-icon>\n </button>\n </div>\n </ng-template>\n </ng-template>\n <ng-template #notAuthenticated>\n <button class=\"odx-auth-sign-in\" odxButton odxAuthSignIn variant=\"primary\" data-testid=\"odx-auth-sign-in-button\">\n <odx-icon name=\"user\" alignLeft></odx-icon>\n {{ signInButtonText }}\n </button>\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</odx-action-group>\n", styles: [".odx-auth-user-profile .odx-dropdown__inner>.odx-area-header{max-width:max(360px,25vw);min-width:296px}\n"], dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.LetDirective, selector: "[ngrxLet]", inputs: ["ngrxLet", "ngrxLetSuspenseTpl"] }, { kind: "ngmodule", type: AreaHeaderModule }, { kind: "component", type: i3.AreaHeaderComponent, selector: "odx-area-header", inputs: ["size"] }, { kind: "directive", type: i3.AreaHeaderSubtitleDirective, selector: "odx-area-header-subtitle" }, { kind: "component", type: i4.AvatarComponent, selector: "odx-avatar", inputs: ["size", "variant"] }, { kind: "component", type: i5.ActionGroupComponent, selector: "odx-action-group", inputs: ["reverse"] }, { kind: "component", type: i6.ButtonComponent, selector: "button[odxButton], a[odxButton]", inputs: ["variant", "size"] }, { kind: "component", type: i7.IconComponent, selector: "odx-icon", inputs: ["inline", "size", "name"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "directive", type: i8.DropdownDirective, selector: "[odxDropdown]", inputs: ["odxDropdown", "odxDropdownDisabled", "odxDropdownShowLoader", "odxDropdownOptions", "odxDropdownReferenceElement", "odxDropdownTriggerElement", "odxDropdownHost", "odxDropdownOpenTrigger", "odxDropdownCloseTrigger"], outputs: ["odxDropdownBeforeOpen", "odxDropdownAfterOpen", "odxDropdownBeforeClose", "odxDropdownAfterClose"], exportAs: ["odxDropdown"] }, { kind: "ngmodule", type: HeaderModule }, { kind: "directive", type: i9.HeaderAvatarDirective, selector: "button[odxButton][odxHeaderAvatar]" }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
253
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthComponent, decorators: [{
179
254
  type: Component,
180
- args: [{ standalone: true, selector: 'odx-auth', imports: [CoreModule, AreaHeaderModule, DropdownModule, HeaderModule, LogoDirective, SignInDirective, SignOutDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<odx-action-group *odxLet=\"authService.user$ | async as user\">\n <ng-template [ngIf]=\"authService.isAuthenticated$ | async\" [ngIfElse]=\"notAuthenticated\">\n <button odxButton odxHeaderAvatar [odxDropdown]=\"userProfileMenu\">\n <odx-avatar>\n {{ getInitials(user) }}\n </odx-avatar>\n </button>\n </ng-template>\n <ng-template #notAuthenticated>\n <button class=\"odx-auth-sign-in\" odxButton odxAuthSignIn variant=\"primary\">\n <odx-icon name=\"user\" alignLeft></odx-icon>\n {{ signInButtonText }}\n </button>\n </ng-template>\n <ng-template #userProfileMenu>\n <odx-area-header class=\"odx-padding-x-12\" size=\"small\">\n <odx-avatar>\n {{ getInitials(user) }}\n </odx-avatar>\n <h2 class=\"odx-title\">{{ user?.name }}</h2>\n <h5 class=\"odx-subtitle\">{{ user?.email_address }}</h5>\n </odx-area-header>\n <ng-content></ng-content>\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\">\n {{ signOutButtonText }}\n <odx-icon name=\"arrow-right\" alignRight></odx-icon>\n </button>\n </div>\n </ng-template>\n</odx-action-group>\n" }]
255
+ args: [{ standalone: true, selector: 'odx-auth', imports: [CoreModule, AreaHeaderModule, DropdownModule, HeaderModule, LogoDirective, SignInDirective, SignOutDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<odx-action-group *ngrxLet=\"{ idClaims: authService.identityClaims$, isAuthenticated: authService.isAuthenticated$ } as vm\">\n <ng-template [ngIf]=\"vm.isAuthenticated\" [ngIfElse]=\"notAuthenticated\">\n <button odxButton odxHeaderAvatar [odxDropdown]=\"userProfileMenu\" [odxDropdownOptions]=\"dropdownOptions\" data-testid=\"odx-auth-user-profile-button\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\"></ng-template>\n </button>\n <ng-template #userProfileMenu>\n <odx-area-header class=\"odx-padding-x-12\" size=\"small\">\n <ng-template [ngTemplateOutlet]=\"userAvatar\" ngProjectAs=\"odx-avatar\"></ng-template>\n {{ vm.idClaims?.name }}\n <odx-area-header-subtitle>\n {{ vm.idClaims?.email }}\n </odx-area-header-subtitle>\n </odx-area-header>\n <ng-content></ng-content>\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 }}\n <odx-icon name=\"arrow-right\" alignRight></odx-icon>\n </button>\n </div>\n </ng-template>\n </ng-template>\n <ng-template #notAuthenticated>\n <button class=\"odx-auth-sign-in\" odxButton odxAuthSignIn variant=\"primary\" data-testid=\"odx-auth-sign-in-button\">\n <odx-icon name=\"user\" alignLeft></odx-icon>\n {{ signInButtonText }}\n </button>\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</odx-action-group>\n", styles: [".odx-auth-user-profile .odx-dropdown__inner>.odx-area-header{max-width:max(360px,25vw);min-width:296px}\n"] }]
181
256
  }], propDecorators: { signInButtonText: [{
182
257
  type: Input
183
258
  }], signOutButtonText: [{
184
259
  type: Input
185
- }], getInitials: [] } });
260
+ }] } });
186
261
 
187
- class AuthInterceptor {
262
+ class AuthDirective {
188
263
  constructor() {
189
- this.config = injectAuthModuleConfig();
190
264
  this.authService = inject(AuthService);
265
+ this.ngIfDirective = inject(NgIf, { host: true });
266
+ this.takeUntilDestroyed = untilDestroyed();
267
+ this.authorizationHandler = null;
191
268
  }
192
- intercept(request, next) {
193
- return next.handle(this.addAuthHeader(request));
269
+ // eslint-disable-next-line @angular-eslint/no-input-rename
270
+ set elseTemplate(value) {
271
+ this.ngIfDirective.ngIfElse = value;
194
272
  }
195
- addAuthHeader(request) {
196
- if (!this.config.disallowedOrigins.find((origin) => !!request.url.match(origin))) {
197
- return request.clone({ setHeaders: this.authService.getAuthHeader() });
198
- }
199
- return request;
273
+ ngAfterViewInit() {
274
+ this.authService.isAuthenticated$.pipe(this.takeUntilDestroyed()).subscribe(() => {
275
+ const handler = isString(this.authorizationHandler) ? null : this.authorizationHandler;
276
+ this.ngIfDirective.ngIf = this.authService.isAuthorized(handler);
277
+ });
200
278
  }
201
279
  }
202
- AuthInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
203
- AuthInterceptorprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthInterceptor });
204
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthInterceptor, decorators: [{
205
- type: Injectable
206
- }] });
280
+ AuthDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
281
+ AuthDirectivedir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.1", type: AuthDirective, isStandalone: true, selector: "ng-template[odxAuth]", inputs: { authorizationHandler: ["odxAuth", "authorizationHandler"], elseTemplate: ["odxAuthElse", "elseTemplate"] }, hostDirectives: [{ directive: i1$1.NgIf }], ngImport: i0 });
282
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthDirective, decorators: [{
283
+ type: Directive,
284
+ args: [{
285
+ standalone: true,
286
+ selector: 'ng-template[odxAuth]',
287
+ hostDirectives: [NgIf],
288
+ }]
289
+ }], propDecorators: { authorizationHandler: [{
290
+ type: Input,
291
+ args: ['odxAuth']
292
+ }], elseTemplate: [{
293
+ type: Input,
294
+ args: ['odxAuthElse']
295
+ }] } });
207
296
 
208
- function registerAuthCallbackRoute() {
209
- const { redirectPath } = injectAuthModuleConfig();
210
- const router = inject(Router);
211
- return () => {
212
- router.config.unshift({ path: redirectPath, component: OktaCallbackComponent });
297
+ function authGuard(authorizedHandler) {
298
+ return (_, state) => {
299
+ const authService = inject(AuthService);
300
+ const router = inject(Router);
301
+ const isAuthorized = () => authorizedHandler?.(authService.getIdentityClaims(), router, authService);
302
+ return authService.isAuthenticated$.pipe(map((isAuthenticated) => {
303
+ if (!isAuthenticated) {
304
+ authService.signIn(state.url);
305
+ }
306
+ return isAuthorized() ?? isAuthenticated;
307
+ }), take(1));
308
+ };
309
+ }
310
+
311
+ function configureInterceptor() {
312
+ const { allowedUrls } = injectAuthModuleConfig();
313
+ return {
314
+ resourceServer: {
315
+ customUrlValidation: (url) => allowedUrls.some((allowedUrl) => !!url.match(allowedUrl)),
316
+ sendAccessToken: true,
317
+ },
213
318
  };
214
319
  }
215
320
  function initalizeAuthConfig() {
216
- const { clientId, scopes, redirectPath, environment, postLogoutRedirectPath, issuerOverride } = injectAuthModuleConfig();
321
+ const { clientId, scopes, redirectPath, environment, postLogoutRedirectUrl, issuer, timeoutFactor, discoveryUrl } = injectAuthModuleConfig();
322
+ const authService = inject(AuthService);
217
323
  const origin = inject(WindowRef).getOrigin();
218
- const postLogoutRedirectUri = postLogoutRedirectPath ? buildUrl(origin, postLogoutRedirectPath) : undefined;
324
+ const scope = Array.from(new Set(DEFAULT_AUTH_SCOPES.concat(scopes ?? []))).join(' ');
325
+ return () => authService.initialize({
326
+ clientId,
327
+ issuer: issuer ?? DEFAULT_ISSUERS[environment],
328
+ scope,
329
+ redirectUri: buildUrl(origin, redirectPath),
330
+ postLogoutRedirectUri: postLogoutRedirectUrl,
331
+ preserveRequestedRoute: true,
332
+ strictDiscoveryDocumentValidation: !discoveryUrl,
333
+ responseType: 'code',
334
+ showDebugInformation: environment === 'dev',
335
+ timeoutFactor,
336
+ });
337
+ }
338
+ function provideAuthErrorHandler(errorHandler) {
219
339
  return {
220
- oktaAuth: new OktaAuth({
221
- issuer: resolveIssuer(environment, issuerOverride),
222
- clientId,
223
- redirectUri: buildUrl(origin, redirectPath),
224
- scopes: Array.from(new Set(DEFAULT_AUTH_SCOPES.concat(scopes ?? []))),
225
- pkce: true,
226
- devMode: environment === 'dev',
227
- postLogoutRedirectUri,
228
- }),
340
+ provide: AuthErrorHandler,
341
+ useClass: errorHandler,
229
342
  };
230
343
  }
231
- var authProviders = [
232
- {
233
- provide: APP_INITIALIZER,
234
- useFactory: registerAuthCallbackRoute,
235
- multi: true,
236
- },
237
- {
238
- provide: OKTA_CONFIG,
239
- useFactory: initalizeAuthConfig,
240
- },
241
- {
242
- provide: HTTP_INTERCEPTORS,
243
- useClass: AuthInterceptor,
244
- multi: true,
245
- },
246
- ];
344
+ function provideAuth(config) {
345
+ return makeEnvironmentProviders([
346
+ provideModuleConfig(AuthModuleConfig, config),
347
+ provideOAuthClient(),
348
+ provideAuthErrorHandler(NoopAuthErrorHandler),
349
+ {
350
+ provide: OAuthModuleConfig,
351
+ useFactory: configureInterceptor,
352
+ },
353
+ {
354
+ provide: APP_INITIALIZER,
355
+ useFactory: initalizeAuthConfig,
356
+ multi: true,
357
+ },
358
+ {
359
+ provide: OAuthStorage,
360
+ useFactory: () => inject(WindowRef).nativeWindow.localStorage,
361
+ },
362
+ ]);
363
+ }
247
364
 
248
- const modules = [AuthComponent, SignInDirective, SignOutDirective];
365
+ const modules = [AuthComponent, AuthDirective, SignInDirective, SignOutDirective];
249
366
  class AuthModule {
250
367
  static forRoot(config) {
251
368
  return {
252
369
  ngModule: AuthModule,
253
- providers: [provideModuleConfig(AuthModuleConfig, config), ...authProviders],
370
+ providers: [provideAuth(config)],
254
371
  };
255
372
  }
256
373
  }
257
- AuthModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
258
- AuthModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.0", ngImport: i0, type: AuthModule, imports: [AuthComponent, SignInDirective, SignOutDirective], exports: [OktaAuthModule, AuthComponent, SignInDirective, SignOutDirective] });
259
- AuthModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthModule, imports: [AuthComponent, OktaAuthModule] });
260
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: AuthModule, decorators: [{
374
+ AuthModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
375
+ AuthModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.1", ngImport: i0, type: AuthModule, imports: [AuthComponent, AuthDirective, SignInDirective, SignOutDirective], exports: [AuthComponent, AuthDirective, SignInDirective, SignOutDirective] });
376
+ AuthModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthModule, imports: [AuthComponent] });
377
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthModule, decorators: [{
261
378
  type: NgModule,
262
379
  args: [{
263
380
  imports: [...modules],
264
- exports: [OktaAuthModule, ...modules],
381
+ exports: [...modules],
265
382
  }]
266
383
  }] });
267
384
 
@@ -269,5 +386,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImpor
269
386
  * Generated bundle index. Do not edit.
270
387
  */
271
388
 
272
- export { AuthComponent, AuthDefaultModuleConfig, AuthInterceptor, AuthModule, AuthModuleConfig, AuthService, DEFAULT_AUTH_SCOPES, SignInDirective, SignOutDirective, getUserInitials, initalizeAuthConfig, injectAuthModuleConfig, registerAuthCallbackRoute, resolveIssuer };
389
+ export { AuthComponent, AuthDefaultModuleConfig, AuthDirective, AuthErrorHandler, AuthModule, AuthModuleConfig, AuthService, DEFAULT_AUTH_SCOPES, DEFAULT_ISSUERS, NoopAuthErrorHandler, SignInDirective, SignOutDirective, authGuard, configureInterceptor, createInititals, initalizeAuthConfig, injectAuthModuleConfig, parseIdentityClaims, provideAuth, provideAuthErrorHandler };
273
390
  //# sourceMappingURL=odx-auth.mjs.map