oidc-client-rx
Version:
ReactiveX enhanced OIDC and OAuth2 protocol support for browser-based JavaScript applications
185 lines (184 loc) • 9.74 kB
JavaScript
import { Injectable, inject } from "injection-js";
import { forkJoin, of, throwError } from "rxjs";
import { catchError, map, switchMap, tap } from "rxjs/operators";
import { AutoLoginService } from "../auto-login/auto-login.service.js";
import { CallbackService } from "../callback/callback.service.js";
import { PeriodicallyTokenCheckService } from "../callback/periodically-token-check.service.js";
import { RefreshSessionService } from "../callback/refresh-session.service.js";
import { CheckSessionService } from "../iframe/check-session.service.js";
import { SilentRenewService } from "../iframe/silent-renew.service.js";
import { LoggerService } from "../logging/logger.service.js";
import { PopUpService } from "../login/popup/popup.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 { UserService } from "../user-data/user.service.js";
import { CurrentUrlService } from "../utils/url/current-url.service.js";
import { AuthStateService } from "./auth-state.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;
}
class CheckAuthService {
getConfig(configuration, url) {
const stateParamFromUrl = this.currentUrlService.getStateParamFromCurrentUrl(url);
return stateParamFromUrl ? this.getConfigurationWithUrlState([
configuration
], stateParamFromUrl) : configuration;
}
checkAuth(configuration, allConfigs, url) {
if (!configuration) return throwError(()=>new Error("Please provide a configuration before setting up the module"));
this.publicEventsService.fireEvent(EventTypes.CheckingAuth);
const stateParamFromUrl = this.currentUrlService.getStateParamFromCurrentUrl(url);
const config = this.getConfig(configuration, url);
if (!config) return throwError(()=>new Error(`could not find matching config for state ${stateParamFromUrl}`));
return this.checkAuthWithConfig(configuration, allConfigs, url);
}
checkAuthMultiple(allConfigs, url) {
const stateParamFromUrl = this.currentUrlService.getStateParamFromCurrentUrl(url);
if (stateParamFromUrl) {
const config = this.getConfigurationWithUrlState(allConfigs, stateParamFromUrl);
if (!config) return throwError(()=>new Error(`could not find matching config for state ${stateParamFromUrl}`));
return this.composeMultipleLoginResults(allConfigs, config, url);
}
const configs = allConfigs;
const allChecks$ = configs.map((x)=>this.checkAuthWithConfig(x, configs, url));
return forkJoin(allChecks$);
}
checkAuthIncludingServer(configuration, allConfigs) {
if (!configuration) return throwError(()=>new Error("Please provide a configuration before setting up the module"));
return this.checkAuthWithConfig(configuration, allConfigs).pipe(switchMap((loginResponse)=>{
const { isAuthenticated } = loginResponse;
if (isAuthenticated) return of(loginResponse);
return this.refreshSessionService.forceRefreshSession(configuration, allConfigs).pipe(tap((loginResponseAfterRefreshSession)=>{
if (loginResponseAfterRefreshSession?.isAuthenticated) this.startCheckSessionAndValidation(configuration, allConfigs);
}));
}));
}
checkAuthWithConfig(config, allConfigs, url) {
if (!config) {
const errorMessage = "Please provide at least one configuration before setting up the module";
this.loggerService.logError(config, errorMessage);
const result = {
isAuthenticated: false,
errorMessage,
userData: null,
idToken: "",
accessToken: "",
configId: ""
};
return of(result);
}
const currentUrl = url || this.currentUrlService.getCurrentUrl();
if (!currentUrl) {
const errorMessage = "No URL found!";
this.loggerService.logError(config, errorMessage);
const result = {
isAuthenticated: false,
errorMessage,
userData: null,
idToken: "",
accessToken: "",
configId: ""
};
return of(result);
}
const { configId, authority } = config;
this.loggerService.logDebug(config, `Working with config '${configId}' using '${authority}'`);
if (this.popupService.isCurrentlyInPopup(config)) {
this.popupService.sendMessageToMainWindow(currentUrl, config);
const result = {
isAuthenticated: false,
errorMessage: "",
userData: null,
idToken: "",
accessToken: "",
configId: ""
};
return of(result);
}
const isCallback = this.callbackService.isCallback(currentUrl, config);
this.loggerService.logDebug(config, `currentUrl to check auth with: '${currentUrl}'`);
const callback$ = isCallback ? this.callbackService.handleCallbackAndFireEvents(currentUrl, config, allConfigs) : of({});
return callback$.pipe(map(()=>{
const isAuthenticated = this.authStateService.areAuthStorageTokensValid(config);
this.loggerService.logDebug(config, `checkAuth completed. Firing events now. isAuthenticated: ${isAuthenticated}`);
if (isAuthenticated) {
this.startCheckSessionAndValidation(config, allConfigs);
if (!isCallback) {
this.authStateService.setAuthenticatedAndFireEvent(allConfigs);
this.userService.publishUserDataIfExists(config, allConfigs);
}
}
this.publicEventsService.fireEvent(EventTypes.CheckingAuthFinished);
const result = {
isAuthenticated,
userData: this.userService.getUserDataFromStore(config),
accessToken: this.authStateService.getAccessToken(config),
idToken: this.authStateService.getIdToken(config),
configId
};
return result;
}), tap(({ isAuthenticated })=>{
if (isAuthenticated) this.autoLoginService.checkSavedRedirectRouteAndNavigate(config);
}), catchError(({ message })=>{
this.loggerService.logError(config, message);
this.publicEventsService.fireEvent(EventTypes.CheckingAuthFinishedWithError, message);
const result = {
isAuthenticated: false,
errorMessage: message,
userData: null,
idToken: "",
accessToken: "",
configId
};
return of(result);
}));
}
startCheckSessionAndValidation(config, allConfigs) {
if (this.checkSessionService.isCheckSessionConfigured(config)) this.checkSessionService.start(config);
this.periodicallyTokenCheckService.startTokenValidationPeriodically(allConfigs, config);
if (this.silentRenewService.isSilentRenewConfigured(config)) this.silentRenewService.getOrCreateIframe(config);
}
getConfigurationWithUrlState(configurations, stateFromUrl) {
if (!stateFromUrl) return null;
for (const config of configurations){
const storedState = this.storagePersistenceService.read("authStateControl", config);
if (storedState === stateFromUrl) return config;
}
return null;
}
composeMultipleLoginResults(configurations, activeConfig, url) {
const allOtherConfigs = configurations.filter((x)=>x.configId !== activeConfig.configId);
const currentConfigResult = this.checkAuthWithConfig(activeConfig, configurations, url);
const allOtherConfigResults = allOtherConfigs.map((config)=>{
const { redirectUrl } = config;
return this.checkAuthWithConfig(config, configurations, redirectUrl);
});
return forkJoin([
currentConfigResult,
...allOtherConfigResults
]);
}
constructor(){
this.checkSessionService = inject(CheckSessionService);
this.currentUrlService = inject(CurrentUrlService);
this.silentRenewService = inject(SilentRenewService);
this.userService = inject(UserService);
this.loggerService = inject(LoggerService);
this.authStateService = inject(AuthStateService);
this.callbackService = inject(CallbackService);
this.refreshSessionService = inject(RefreshSessionService);
this.periodicallyTokenCheckService = inject(PeriodicallyTokenCheckService);
this.popupService = inject(PopUpService);
this.autoLoginService = inject(AutoLoginService);
this.storagePersistenceService = inject(StoragePersistenceService);
this.publicEventsService = inject(PublicEventsService);
}
}
CheckAuthService = _ts_decorate([
Injectable()
], CheckAuthService);
export { CheckAuthService };