oidc-client-rx
Version:
ReactiveX enhanced OIDC and OAuth2 protocol support for browser-based JavaScript applications
136 lines (135 loc) • 7.74 kB
JavaScript
import { HttpHeaders } from "@ngify/http";
import { Injectable, inject } from "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 };