UNPKG

@okta/okta-angular

Version:
473 lines (459 loc) 23.9 kB
import * as i0 from '@angular/core'; import { InjectionToken, Injectable, Optional, Inject, Component, VERSION, Directive, Input, NgModule } from '@angular/core'; import { Router, NavigationStart } from '@angular/router'; import { Location } from '@angular/common'; import * as i2 from '@okta/okta-auth-js'; import { AuthSdkError, toRelativeUrl } from '@okta/okta-auth-js'; import { filter, mergeMap, switchMap, takeUntil } from 'rxjs/operators'; import { BehaviorSubject, ReplaySubject, Subject } from 'rxjs'; import { compare } from 'compare-versions'; /* * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") * * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and limitations under the License. */ const OKTA_CONFIG = new InjectionToken('okta.config.angular'); const OKTA_AUTH = new InjectionToken('okta.auth'); class OktaAuthConfigService { constructor(config) { if (config) { this.config = config; } } getConfig() { return this.config; } setConfig(config) { this.config = config; } } OktaAuthConfigService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthConfigService, deps: [{ token: OKTA_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); OktaAuthConfigService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthConfigService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthConfigService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [OKTA_CONFIG] }] }]; } }); var __awaiter$3 = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; class OktaCallbackComponent { constructor(configService, oktaAuth, injector) { this.configService = configService; this.oktaAuth = oktaAuth; this.injector = injector; } ngOnInit() { return __awaiter$3(this, void 0, void 0, function* () { const config = this.configService.getConfig(); if (!config) { throw new Error('Okta config is not provided'); } try { // Parse code or tokens from the URL, store tokens in the TokenManager, and redirect back to the originalUri yield this.oktaAuth.handleLoginRedirect(); } catch (e) { // Callback from social IDP. Show custom login page to continue. // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Supports auth-js v5 & v6-7 const isInteractionRequiredError = this.oktaAuth.isInteractionRequiredError || this.oktaAuth.idx.isInteractionRequiredError; if (isInteractionRequiredError(e) && this.injector) { const { onAuthResume, onAuthRequired } = config; const callbackFn = onAuthResume || onAuthRequired; if (callbackFn) { callbackFn(this.oktaAuth, this.injector); return; } } this.error = e.toString(); } }); } } OktaCallbackComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaCallbackComponent, deps: [{ token: OktaAuthConfigService }, { token: OKTA_AUTH }, { token: i0.Injector, optional: true }], target: i0.ɵɵFactoryTarget.Component }); OktaCallbackComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.17", type: OktaCallbackComponent, selector: "ng-component", ngImport: i0, template: `<div>{{error}}</div>`, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaCallbackComponent, decorators: [{ type: Component, args: [{ template: `<div>{{error}}</div>` }] }], ctorParameters: function () { return [{ type: OktaAuthConfigService }, { type: i2.OktaAuth, decorators: [{ type: Inject, args: [OKTA_AUTH] }] }, { type: i0.Injector, decorators: [{ type: Optional }] }]; } }); var __awaiter$2 = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; class OktaAuthGuard { constructor(oktaAuth, injector, configService) { this.oktaAuth = oktaAuth; this.injector = injector; this.configService = configService; this.updateAuthStateListener = (authState) => __awaiter$2(this, void 0, void 0, function* () { const isAuthenticated = yield this.isAuthenticated(this.routeData, authState); if (!isAuthenticated) { this.handleLogin(this.state.url, this.routeData); } }); const config = this.configService.getConfig(); if (!config) { throw new Error('Okta config is not provided'); } this.onAuthRequired = config.onAuthRequired; // Unsubscribe updateAuthStateListener when route change const router = injector.get(Router); router.events.pipe(filter((e) => e instanceof NavigationStart && this.state && this.state.url !== e.url)).subscribe(() => { this.oktaAuth.authStateManager.unsubscribe(this.updateAuthStateListener); }); } canLoad(route) { var _a; return __awaiter$2(this, void 0, void 0, function* () { this.onAuthRequired = ((_a = route.data) === null || _a === void 0 ? void 0 : _a.onAuthRequired) || this.onAuthRequired; const isAuthenticated = yield this.isAuthenticated(route.data); if (isAuthenticated) { return true; } const router = this.injector.get(Router); const nav = router.getCurrentNavigation(); const originalUri = nav ? nav.extractedUrl.toString() : undefined; yield this.handleLogin(originalUri, route.data); return false; }); } /** * Gateway for protected route. Returns true if there is a valid idToken, * otherwise it will cache the route and start the login flow. * @param route * @param state */ canActivate(route, state) { return __awaiter$2(this, void 0, void 0, function* () { // Track states for current route this.state = state; this.routeData = route.data; this.onAuthRequired = route.data && route.data.onAuthRequired || this.onAuthRequired; // Protect the route after accessing this.oktaAuth.authStateManager.subscribe(this.updateAuthStateListener); const isAuthenticated = yield this.isAuthenticated(route.data); if (isAuthenticated) { return true; } yield this.handleLogin(state.url, route.data); return false; }); } canActivateChild(route, state) { return __awaiter$2(this, void 0, void 0, function* () { return this.canActivate(route, state); }); } isAuthenticated(routeData, authState) { var _a, _b, _c; return __awaiter$2(this, void 0, void 0, function* () { const isAuthenticated = authState ? authState === null || authState === void 0 ? void 0 : authState.isAuthenticated : yield this.oktaAuth.isAuthenticated(); let res = isAuthenticated; if ((_a = routeData === null || routeData === void 0 ? void 0 : routeData.okta) === null || _a === void 0 ? void 0 : _a.acrValues) { if (!authState) { authState = this.oktaAuth.authStateManager.getAuthState(); } res = ((_b = authState === null || authState === void 0 ? void 0 : authState.idToken) === null || _b === void 0 ? void 0 : _b.claims.acr) === ((_c = routeData === null || routeData === void 0 ? void 0 : routeData.okta) === null || _c === void 0 ? void 0 : _c.acrValues); } return res; }); } handleLogin(originalUri, routeData) { var _a; return __awaiter$2(this, void 0, void 0, function* () { // Store the current path if (originalUri) { this.oktaAuth.setOriginalUri(originalUri); } const options = {}; if ((_a = routeData === null || routeData === void 0 ? void 0 : routeData.okta) === null || _a === void 0 ? void 0 : _a.acrValues) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Supports auth-js >= 7.1.0 options.acrValues = routeData.okta.acrValues; } if (this.onAuthRequired) { this.onAuthRequired(this.oktaAuth, this.injector, options); } else { this.oktaAuth.signInWithRedirect(options); } }); } } OktaAuthGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthGuard, deps: [{ token: OKTA_AUTH }, { token: i0.Injector }, { token: OktaAuthConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); OktaAuthGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthGuard }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthGuard, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i2.OktaAuth, decorators: [{ type: Inject, args: [OKTA_AUTH] }] }, { type: i0.Injector }, { type: OktaAuthConfigService }]; } }); var __awaiter$1 = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; const defaultAuthState = { isAuthenticated: false }; class OktaAuthStateService { constructor(oktaAuth) { this.oktaAuth = oktaAuth; this._authState = new BehaviorSubject(defaultAuthState); // only expose readonly property this.authState$ = this._authState.asObservable(); this.updateAuthState = this.updateAuthState.bind(this); // set initial authState const initialAuthState = this.oktaAuth.authStateManager.getAuthState() || defaultAuthState; this._authState.next(initialAuthState); // subscribe to future changes this.oktaAuth.authStateManager.subscribe(this.updateAuthState); } ngOnDestroy() { this.oktaAuth.authStateManager.unsubscribe(this.updateAuthState); } // Observes as true when any group input can match groups from user claims hasAnyGroups(groups) { return this.authState$.pipe(mergeMap(({ isAuthenticated, idToken }) => __awaiter$1(this, void 0, void 0, function* () { // return false when not authenticated or openid is not in scopes if (!isAuthenticated || !idToken) { return false; } // transform inputs to consistent object format if (typeof groups === 'string') { groups = { groups: [groups] }; } if (Array.isArray(groups)) { groups = { groups }; } const key = Object.keys(groups)[0]; const value = groups[key]; // groups or custom claims is available in idToken if (idToken.claims[key]) { return value.some((authority) => idToken.claims[key].includes(authority)); } // try /userinfo endpoint when thin idToken (no groups claim) is returned // https://developer.okta.com/docs/concepts/api-access-management/#tokens-and-scopes const userInfo = yield this.oktaAuth.getUser(); if (!userInfo[key]) { return false; } return value.some((authority) => userInfo[key].includes(authority)); }))); } updateAuthState(authState) { this._authState.next(authState); } } OktaAuthStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthStateService, deps: [{ token: OKTA_AUTH }], target: i0.ɵɵFactoryTarget.Injectable }); OktaAuthStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthStateService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthStateService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i2.OktaAuth, decorators: [{ type: Inject, args: [OKTA_AUTH] }] }]; } }); var packageInfo = { 'name': '@okta/okta-angular', 'version': '6.5.1', 'authJSMinSupportedVersion': '5.3.1' }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; class OktaAuthFactoryService { static setupOktaAuth(oktaAuth, router, location) { const isAuthJsSupported = oktaAuth._oktaUserAgent && compare(oktaAuth._oktaUserAgent.getVersion(), packageInfo.authJSMinSupportedVersion, '>='); if (!isAuthJsSupported) { throw new AuthSdkError(`Passed in oktaAuth is not compatible with the SDK, minimum supported okta-auth-js version is ${packageInfo.authJSMinSupportedVersion}.`); } // Add Okta UA oktaAuth._oktaUserAgent.addEnvironment(`${packageInfo.name}/${packageInfo.version}`); oktaAuth._oktaUserAgent.addEnvironment(`Angular/${VERSION.full}`); // Provide a default implementation of `restoreOriginalUri` if (!oktaAuth.options.restoreOriginalUri && router && location) { oktaAuth.options.restoreOriginalUri = (_, originalUri) => __awaiter(this, void 0, void 0, function* () { const baseUrl = window.location.origin + location.prepareExternalUrl(''); const routePath = toRelativeUrl(originalUri || '/', baseUrl); router.navigateByUrl(routePath); }); } // Start services oktaAuth.start(); } static createOktaAuth(configService, router, location) { const config = configService.getConfig(); if (!config) { throw new Error('Okta config is not provided'); } const { oktaAuth } = config; if (!oktaAuth) { throw new Error('Okta config should contain oktaAuth'); } OktaAuthFactoryService.setupOktaAuth(oktaAuth, router, location); return oktaAuth; } } class OktaHasAnyGroupDirective { constructor( // eslint-disable-next-line @typescript-eslint/no-explicit-any templateRef, viewContainer, authStateService) { this.templateRef = templateRef; this.viewContainer = viewContainer; this.authStateService = authStateService; this.groupsSub$ = new ReplaySubject(); this.destroySub$ = new Subject(); } ngOnInit() { this.groupsSub$.pipe(filter(groups => !!groups), switchMap(groups => this.authStateService.hasAnyGroups(groups)), takeUntil(this.destroySub$)).subscribe(isAuthorized => { this.viewContainer.clear(); if (isAuthorized) { this.viewContainer.createEmbeddedView(this.templateRef); } }); } ngOnChanges(changes) { if (changes['oktaHasAnyGroup'].currentValue !== changes['oktaHasAnyGroup'].previousValue) { this.groupsSub$.next(changes['oktaHasAnyGroup'].currentValue); } } ngOnDestroy() { this.destroySub$.next(); this.destroySub$.complete(); } } OktaHasAnyGroupDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaHasAnyGroupDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: OktaAuthStateService }], target: i0.ɵɵFactoryTarget.Directive }); OktaHasAnyGroupDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.17", type: OktaHasAnyGroupDirective, selector: "[oktaHasAnyGroup]", inputs: { oktaHasAnyGroup: "oktaHasAnyGroup" }, usesOnChanges: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaHasAnyGroupDirective, decorators: [{ type: Directive, args: [{ selector: '[oktaHasAnyGroup]' }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: OktaAuthStateService }]; }, propDecorators: { oktaHasAnyGroup: [{ type: Input }] } }); /* * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") * * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and limitations under the License. */ class OktaAuthModule { static forRoot(config) { return { ngModule: OktaAuthModule, providers: [ { provide: OKTA_CONFIG, useValue: config }, ] }; } } OktaAuthModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); OktaAuthModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthModule, declarations: [OktaCallbackComponent, OktaHasAnyGroupDirective], exports: [OktaCallbackComponent, OktaHasAnyGroupDirective] }); OktaAuthModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthModule, providers: [ OktaAuthConfigService, OktaAuthStateService, OktaAuthGuard, { provide: OKTA_AUTH, useFactory: OktaAuthFactoryService.createOktaAuth, deps: [ OktaAuthConfigService, [new Optional(), Router], [new Optional(), Location] ] }, ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: OktaAuthModule, decorators: [{ type: NgModule, args: [{ declarations: [ OktaCallbackComponent, OktaHasAnyGroupDirective, ], exports: [ OktaCallbackComponent, OktaHasAnyGroupDirective, ], providers: [ OktaAuthConfigService, OktaAuthStateService, OktaAuthGuard, { provide: OKTA_AUTH, useFactory: OktaAuthFactoryService.createOktaAuth, deps: [ OktaAuthConfigService, [new Optional(), Router], [new Optional(), Location] ] }, ] }] }] }); /* * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") * * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and limitations under the License. */ /** * Entry point for all public APIs of the package. */ // This file only reexports content of the `src` folder. Keep it that way. /** * Generated bundle index. Do not edit. */ export { OKTA_AUTH, OKTA_CONFIG, OktaAuthConfigService, OktaAuthGuard, OktaAuthModule, OktaAuthStateService, OktaCallbackComponent, OktaHasAnyGroupDirective }; //# sourceMappingURL=okta-okta-angular.js.map