UNPKG

oidc-client-rx

Version:

ReactiveX enhanced OIDC and OAuth2 protocol support for browser-based JavaScript applications

166 lines (165 loc) 8.13 kB
import { Injectable, inject } from "injection-js"; import { BehaviorSubject, throwError } from "rxjs"; import { distinctUntilChanged } from "rxjs/operators"; import { LoggerService } from "../logging/logger.service.js"; import { EventTypes } from "../public-events/event-types.js"; import { PublicEventsService } from "../public-events/public-events.service.js"; import { StoragePersistenceService } from "../storage/storage-persistence.service.js"; import { TokenValidationService } from "../validation/token-validation.service.js"; function _ts_decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : null === desc ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if ("object" == typeof Reflect && "function" == typeof Reflect.decorate) r = Reflect.decorate(decorators, target, key, desc); else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } const DEFAULT_AUTHRESULT = { isAuthenticated: false, allConfigsAuthenticated: [] }; class AuthStateService { get authenticated$() { return this.authenticatedInternal$.asObservable().pipe(distinctUntilChanged()); } setAuthenticatedAndFireEvent(allConfigs) { const result = this.composeAuthenticatedResult(allConfigs); this.authenticatedInternal$.next(result); } setUnauthenticatedAndFireEvent(currentConfig, allConfigs) { this.storagePersistenceService.resetAuthStateInStorage(currentConfig); const result = this.composeUnAuthenticatedResult(allConfigs); this.authenticatedInternal$.next(result); } updateAndPublishAuthState(authenticationResult) { this.publicEventsService.fireEvent(EventTypes.NewAuthenticationResult, authenticationResult); } setAuthorizationData(accessToken, authResult, currentConfig, allConfigs) { this.loggerService.logDebug(currentConfig, `storing the accessToken '${accessToken}'`); this.storagePersistenceService.write("authzData", accessToken, currentConfig); this.persistAccessTokenExpirationTime(authResult, currentConfig); this.setAuthenticatedAndFireEvent(allConfigs); } getAccessToken(configuration) { if (!configuration) return ""; if (!this.isAuthenticated(configuration)) return ""; const token = this.storagePersistenceService.getAccessToken(configuration); return this.decodeURIComponentSafely(token); } getIdToken(configuration) { if (!configuration) return ""; if (!this.isAuthenticated(configuration)) return ""; const token = this.storagePersistenceService.getIdToken(configuration); return this.decodeURIComponentSafely(token); } getRefreshToken(configuration) { if (!configuration) return ""; if (!this.isAuthenticated(configuration)) return ""; const token = this.storagePersistenceService.getRefreshToken(configuration); return this.decodeURIComponentSafely(token); } getAuthenticationResult(configuration) { if (!configuration) return null; if (!this.isAuthenticated(configuration)) return null; return this.storagePersistenceService.getAuthenticationResult(configuration); } areAuthStorageTokensValid(configuration) { if (!configuration) return false; if (!this.isAuthenticated(configuration)) return false; if (this.hasIdTokenExpiredAndRenewCheckIsEnabled(configuration)) { this.loggerService.logDebug(configuration, "persisted idToken is expired"); return false; } if (this.hasAccessTokenExpiredIfExpiryExists(configuration)) { this.loggerService.logDebug(configuration, "persisted accessToken is expired"); return false; } this.loggerService.logDebug(configuration, "persisted idToken and accessToken are valid"); return true; } hasIdTokenExpiredAndRenewCheckIsEnabled(configuration) { const { renewTimeBeforeTokenExpiresInSeconds, triggerRefreshWhenIdTokenExpired, disableIdTokenValidation } = configuration; if (!triggerRefreshWhenIdTokenExpired || disableIdTokenValidation) return false; const tokenToCheck = this.storagePersistenceService.getIdToken(configuration); const idTokenExpired = this.tokenValidationService.hasIdTokenExpired(tokenToCheck, configuration, renewTimeBeforeTokenExpiresInSeconds); if (idTokenExpired) this.publicEventsService.fireEvent(EventTypes.IdTokenExpired, idTokenExpired); return idTokenExpired; } hasAccessTokenExpiredIfExpiryExists(configuration) { const { renewTimeBeforeTokenExpiresInSeconds } = configuration; const accessTokenExpiresIn = this.storagePersistenceService.read("access_token_expires_at", configuration); const accessTokenHasNotExpired = this.tokenValidationService.validateAccessTokenNotExpired(accessTokenExpiresIn, configuration, renewTimeBeforeTokenExpiresInSeconds); const hasExpired = !accessTokenHasNotExpired; if (hasExpired) this.publicEventsService.fireEvent(EventTypes.TokenExpired, hasExpired); return hasExpired; } isAuthenticated(configuration) { if (!configuration) { throwError(()=>new Error("Please provide a configuration before setting up the module")); return false; } const hasAccessToken = !!this.storagePersistenceService.getAccessToken(configuration); const hasIdToken = !!this.storagePersistenceService.getIdToken(configuration); return hasAccessToken && hasIdToken; } decodeURIComponentSafely(token) { if (token) return decodeURIComponent(token); return ""; } persistAccessTokenExpirationTime(authResult, configuration) { if (authResult?.expires_in) { const accessTokenExpiryTime = new Date(new Date().toUTCString()).valueOf() + 1000 * authResult.expires_in; this.storagePersistenceService.write("access_token_expires_at", accessTokenExpiryTime, configuration); } } composeAuthenticatedResult(allConfigs) { if (1 === allConfigs.length) { const { configId } = allConfigs[0]; return { isAuthenticated: true, allConfigsAuthenticated: [ { configId: configId ?? "", isAuthenticated: true } ] }; } return this.checkallConfigsIfTheyAreAuthenticated(allConfigs); } composeUnAuthenticatedResult(allConfigs) { if (1 === allConfigs.length) { const { configId } = allConfigs[0]; return { isAuthenticated: false, allConfigsAuthenticated: [ { configId: configId ?? "", isAuthenticated: false } ] }; } return this.checkallConfigsIfTheyAreAuthenticated(allConfigs); } checkallConfigsIfTheyAreAuthenticated(allConfigs) { const allConfigsAuthenticated = allConfigs.map((config)=>({ configId: config.configId ?? "", isAuthenticated: this.isAuthenticated(config) })); const isAuthenticated = allConfigsAuthenticated.every((x)=>!!x.isAuthenticated); return { allConfigsAuthenticated, isAuthenticated }; } constructor(){ this.storagePersistenceService = inject(StoragePersistenceService); this.loggerService = inject(LoggerService); this.publicEventsService = inject(PublicEventsService); this.tokenValidationService = inject(TokenValidationService); this.authenticatedInternal$ = new BehaviorSubject(DEFAULT_AUTHRESULT); } } AuthStateService = _ts_decorate([ Injectable() ], AuthStateService); export { AuthStateService };