import { UserManager, WebStorageStateStore } from'oidc-client';
import { ApplicationPaths, ApplicationName } from'./ApiAuthorizationConstants';
exportclassAuthorizeService{
_callbacks = [];
_nextSubscriptionId = 0;
_user = null;
_isAuthenticated = false;
// By default pop ups are disabled because they don't work properly on Edge.// If you want to enable pop up authentication simply set this flag to false.
_popUpDisabled = true;
async isAuthenticated() {
const user = awaitthis.getUser();
return !!user;
}
async getUser() {
if (this._user && this._user.profile) {
returnthis._user.profile;
}
awaitthis.ensureUserManagerInitialized();
const user = awaitthis.userManager.getUser();
return user && user.profile;
}
async getAccessToken() {
awaitthis.ensureUserManagerInitialized();
const user = awaitthis.userManager.getUser();
return user && user.access_token;
}
// We try to authenticate the user in three different ways:// 1) We try to see if we can authenticate the user silently. This happens// when the user is already logged in on the IdP and is done using a hidden iframe// on the client.// 2) We try to authenticate the user using a PopUp Window. This might fail if there is a// Pop-Up blocker or the user has disabled PopUps.// 3) If the two methods above fail, we redirect the browser to the IdP to perform a traditional// redirect flow.async signIn(state) {
awaitthis.ensureUserManagerInitialized();
try {
const silentUser = awaitthis.userManager.signinSilent(this.createArguments());
this.updateState(silentUser);
returnthis.success(state);
} catch (silentError) {
// User might not be authenticated, fallback to popup authenticationconsole.log("Silent authentication error: ", silentError);
try {
if (this._popUpDisabled) {
thrownewError('Popup disabled. Change \'AuthorizeService.js:AuthorizeService._popupDisabled\' to false to enable it.')
}
const popUpUser = awaitthis.userManager.signinPopup(this.createArguments());
this.updateState(popUpUser);
returnthis.success(state);
} catch (popUpError) {
if (popUpError.message === "Popup window closed") {
// The user explicitly cancelled the login action by closing an opened popup.returnthis.error("The user closed the window.");
} elseif (!this._popUpDisabled) {
console.log("Popup authentication error: ", popUpError);
}
// PopUps might be blocked by the user, fallback to redirecttry {
awaitthis.userManager.signinRedirect(this.createArguments(state));
returnthis.redirect();
} catch (redirectError) {
console.log("Redirect authentication error: ", redirectError);
returnthis.error(redirectError);
}
}
}
}
async completeSignIn(url) {
try {
awaitthis.ensureUserManagerInitialized();
const user = awaitthis.userManager.signinCallback(url);
this.updateState(user);
returnthis.success(user && user.state);
} catch (error) {
console.log('There was an error signing in: ', error);
returnthis.error('There was an error signing in.');
}
}
// We try to sign out the user in two different ways:// 1) We try to do a sign-out using a PopUp Window. This might fail if there is a// Pop-Up blocker or the user has disabled PopUps.// 2) If the method above fails, we redirect the browser to the IdP to perform a traditional// post logout redirect flow.async signOut(state) {
awaitthis.ensureUserManagerInitialized();
try {
if (this._popUpDisabled) {
thrownewError('Popup disabled. Change \'AuthorizeService.js:AuthorizeService._popupDisabled\' to false to enable it.')
}
awaitthis.userManager.signoutPopup(this.createArguments());
this.updateState(undefined);
returnthis.success(state);
} catch (popupSignOutError) {
console.log("Popup signout error: ", popupSignOutError);
try {
awaitthis.userManager.signoutRedirect(this.createArguments(state));
returnthis.redirect();
} catch (redirectSignOutError) {
console.log("Redirect signout error: ", redirectSignOutError);
returnthis.error(redirectSignOutError);
}
}
}
async completeSignOut(url) {
awaitthis.ensureUserManagerInitialized();
try {
const response = awaitthis.userManager.signoutCallback(url);
this.updateState(null);
returnthis.success(response && response.data);
} catch (error) {
console.log(`There was an error trying to log out '${error}'.`);
returnthis.error(error);
}
}
updateState(user) {
this._user = user;
this._isAuthenticated = !!this._user;
this.notifySubscribers();
}
subscribe(callback) {
this._callbacks.push({ callback, subscription: this._nextSubscriptionId++ });
returnthis._nextSubscriptionId - 1;
}
unsubscribe(subscriptionId) {
const subscriptionIndex = this._callbacks
.map((element, index) => element.subscription === subscriptionId ? { found: true, index } : { found: false })
.filter(element => element.found === true);
if (subscriptionIndex.length !== 1) {
thrownewError(`Found an invalid number of subscriptions ${subscriptionIndex.length}`);
}
this._callbacks.splice(subscriptionIndex[0].index, 1);
}
notifySubscribers() {
for (let i = 0; i < this._callbacks.length; i++) {
const callback = this._callbacks[i].callback;
callback();
}
}
createArguments(state) {
return { useReplaceToNavigate: true, data: state };
}
error(message) {
return { status: AuthenticationResultStatus.Fail, message };
}
success(state) {
return { status: AuthenticationResultStatus.Success, state };
}
redirect() {
return { status: AuthenticationResultStatus.Redirect };
}
async ensureUserManagerInitialized() {
if (this.userManager !== undefined) {
return;
}
let response = await fetch(ApplicationPaths.ApiAuthorizationClientConfigurationUrl);
if (!response.ok) {
thrownewError(`Could not load settings for '${ApplicationName}'`);
}
let settings = await response.json();
settings.automaticSilentRenew = true;
settings.includeIdTokenInSilentRenew = true;
settings.userStore = new WebStorageStateStore({
prefix: ApplicationName
});
this.userManager = new UserManager(settings);
this.userManager.events.addUserSignedOut(async () => {
awaitthis.userManager.removeUser();
this.updateState(undefined);
});
}
static get instance() { return authService }
}
const authService = new AuthorizeService();
exportdefault authService;
exportconst AuthenticationResultStatus = {
Redirect: 'redirect',
Success: 'success',
Fail: 'fail'
};