oidc-client-rx
Version:
ReactiveX enhanced OIDC and OAuth2 protocol support for browser-based JavaScript applications
134 lines (133 loc) • 7.73 kB
JavaScript
import { HttpHeaders } from "@ngify/http";
import { Injectable, inject } from "@outposts/injection-js";
import { of, throwError } from "rxjs";
import { catchError, concatMap, retry, switchMap } from "rxjs/operators";
import { DataService } from "../api/data.service.js";
import { ResetAuthDataService } from "../flows/reset-auth-data.service.js";
import { CheckSessionService } from "../iframe/check-session.service.js";
import { LoggerService } from "../logging/logger.service.js";
import { StoragePersistenceService } from "../storage/storage-persistence.service.js";
import { removeNullAndUndefinedValues } from "../utils/object/object.helper.js";
import { RedirectService } from "../utils/redirect/redirect.service.js";
import { UrlService } from "../utils/url/url.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 LogoffRevocationService {
logoff(config, allConfigs, logoutAuthOptions) {
if (!config) return throwError(()=>new Error('Please provide a configuration before setting up the module'));
this.loggerService.logDebug(config, 'logoff, remove auth', logoutAuthOptions);
const { urlHandler, customParams } = logoutAuthOptions || {};
const endSessionUrl = this.urlService.getEndSessionUrl(config, customParams);
if (!endSessionUrl) {
this.loggerService.logDebug(config, 'No endsessionUrl present. Logoff was only locally. Returning.');
return of(null);
}
if (this.checkSessionService.serverStateChanged(config)) {
this.loggerService.logDebug(config, 'Server State changed. Logoff was only locally. Returning.');
return of(null);
}
if (urlHandler) {
this.loggerService.logDebug(config, `Custom UrlHandler found. Using this to handle logoff with url '${endSessionUrl}'`);
urlHandler(endSessionUrl);
this.resetAuthDataService.resetAuthorizationData(config, allConfigs);
return of(null);
}
return this.logoffInternal(logoutAuthOptions, endSessionUrl, config, allConfigs);
}
logoffLocal(config, allConfigs) {
this.resetAuthDataService.resetAuthorizationData(config, allConfigs);
this.checkSessionService.stop();
}
logoffLocalMultiple(allConfigs) {
allConfigs.forEach((configuration)=>this.logoffLocal(configuration, allConfigs));
}
logoffAndRevokeTokens(config, allConfigs, logoutAuthOptions) {
if (!config) return throwError(()=>new Error('Please provide a configuration before setting up the module'));
const { revocationEndpoint } = this.storagePersistenceService.read('authWellKnownEndPoints', config) || {};
if (!revocationEndpoint) {
this.loggerService.logDebug(config, 'revocation endpoint not supported');
return this.logoff(config, allConfigs, logoutAuthOptions);
}
if (this.storagePersistenceService.getRefreshToken(config)) return this.revokeRefreshToken(config).pipe(switchMap((_)=>this.revokeAccessToken(config)), catchError((error)=>{
const errorMessage = 'revoke token failed';
this.loggerService.logError(config, errorMessage, error);
return throwError(()=>new Error(errorMessage));
}), concatMap(()=>this.logoff(config, allConfigs, logoutAuthOptions)));
return this.revokeAccessToken(config).pipe(catchError((error)=>{
const errorMessage = 'revoke accessToken failed';
this.loggerService.logError(config, errorMessage, error);
return throwError(()=>new Error(errorMessage));
}), concatMap(()=>this.logoff(config, allConfigs, logoutAuthOptions)));
}
revokeAccessToken(configuration, accessToken) {
if (!configuration) return throwError(()=>new Error('Please provide a configuration before setting up the module'));
const accessTok = accessToken || this.storagePersistenceService.getAccessToken(configuration);
const body = this.urlService.createRevocationEndpointBodyAccessToken(accessTok, configuration);
return this.sendRevokeRequest(configuration, body);
}
revokeRefreshToken(configuration, refreshToken) {
if (!configuration) return throwError(()=>new Error('Please provide a configuration before setting up the module'));
const refreshTok = refreshToken || this.storagePersistenceService.getRefreshToken(configuration);
const body = this.urlService.createRevocationEndpointBodyRefreshToken(refreshTok, configuration);
return this.sendRevokeRequest(configuration, body);
}
logoffInternal(logoutAuthOptions, endSessionUrl, config, allConfigs) {
const { logoffMethod, customParams } = logoutAuthOptions || {};
if (!logoffMethod || 'GET' === logoffMethod) {
this.redirectService.redirectTo(endSessionUrl);
this.resetAuthDataService.resetAuthorizationData(config, allConfigs);
return of(null);
}
const { state, logout_hint, ui_locales } = customParams || {};
const { clientId } = config;
const idToken = this.storagePersistenceService.getIdToken(config);
const postLogoutRedirectUrl = this.urlService.getPostLogoutRedirectUrl(config);
const headers = this.getHeaders();
const { url } = this.urlService.getEndSessionEndpoint(config);
const body = {
id_token_hint: idToken,
client_id: clientId,
post_logout_redirect_uri: postLogoutRedirectUrl,
state,
logout_hint,
ui_locales
};
const bodyWithoutNullOrUndefined = removeNullAndUndefinedValues(body);
this.resetAuthDataService.resetAuthorizationData(config, allConfigs);
return this.dataService.post(url, bodyWithoutNullOrUndefined, config, headers);
}
sendRevokeRequest(configuration, body) {
const url = this.urlService.getRevocationEndpointUrl(configuration);
const headers = this.getHeaders();
return this.dataService.post(url, body, configuration, headers).pipe(retry(2), switchMap((response)=>{
this.loggerService.logDebug(configuration, 'revocation endpoint post response: ', response);
return of(response);
}), catchError((error)=>{
const errorMessage = 'Revocation request failed';
this.loggerService.logError(configuration, errorMessage, error);
return throwError(()=>new Error(errorMessage));
}));
}
getHeaders() {
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/x-www-form-urlencoded');
return headers;
}
constructor(){
this.loggerService = inject(LoggerService);
this.dataService = inject(DataService);
this.storagePersistenceService = inject(StoragePersistenceService);
this.urlService = inject(UrlService);
this.checkSessionService = inject(CheckSessionService);
this.resetAuthDataService = inject(ResetAuthDataService);
this.redirectService = inject(RedirectService);
}
}
LogoffRevocationService = _ts_decorate([
Injectable()
], LogoffRevocationService);
export { LogoffRevocationService };