Reputation: 127
I am trying to let my user renew their SSO token by the following steps:
-If detecting expiry, prompt user with modal asking User to Sign in: -If user confirms (clicks 'launch'), launch window with sso url -Once launched, detect token from new window, set it as new access token, and close window
The window is launched inside of a setInterval function, and I do not know how to return the boolean result of whether a success occurred of this to the calling function. Below is the relevant code, how can I return the boolean result from inside setInterval?
refreshSSO opens the matDialog. If user selects 'launch', opens goes to doAuth to launch SSO window and detect new token
refreshSSO(): Observable<boolean> {
const refresh_uri = <sso endpoint>;
const config = matDialogHelpers.getDefaultConfig({});
const matDialogRef: MatDialogRef<LaunchRefreshComponent> = this.matDialog.open(LaunchRefreshComponent, config);
return matDialogRef.afterClosed().pipe(
map(
next => {
if (next === 'launch') {
return this.popupAuth(refresh_uri);
} else {
return false;
}
})
);
}
popupAuth(authUrl: string): boolean {
this.intervalId = window.setInterval(() => { this.insideInterval(authUrl); }, this.intervalLength);
return this.intervalId;
}
insideInterval opens the window with the sso, counts down the time, and checks for new accessToken. If found, sets the token, returns true, and closes. If time runs out, returns false and closes.
insideInterval(authUrl: string): boolean {
let windowHandle: Window;
let loopCount = this.loopCount;
/* Create the window object by passing url and optional window title */
windowHandle = this.createOauthWindow(authUrl, 'OAuth login');
if (loopCount-- < 0) {
window.clearInterval(this.intervalId);
windowHandle.close();
return false;
} else {
let href: string; // For referencing window url
try {
href = windowHandle.location.href; // set window location to href string
} catch (e) {
console.log('Error:', e); // Handle any errors here
}
if (href != null) {
/* As i was getting code and oauth-token i added for same, you can replace with your expected variables */
if (href.match('access_token')) {
// for twitter
window.clearInterval(this.intervalId);
const newToken = this.getQueryString('access_token', href);
localStorage.setItem('accessToken', newToken);
windowHandle.close();
return true;
}
}
}
}
createOauthWindow simply opens a pop-up with the given URL
createOauthWindow(url: string, name = 'Authorization', width = 500, height = 600, left = 0, top = 0) {
if (url == null) {
return null;
}
const options = `width=${width},height=${height},left=${left},top=${top}`;
return window.open(url, name, options);
}
Upvotes: 0
Views: 64
Reputation: 1433
Consider keeping it RxJs: https://www.learnrxjs.io/learn-rxjs/operators/creation/timer
popupAuth(authUrl: string): Observable<boolean> {
return timer(this.intervalLength, this.intervalLength).pipe(
map(() => this.insideInterval(authUrl))
)
}
Then, you can use the appropriate map inside refreshSSO
.
Check out this article: https://blog.angular-university.io/rxjs-higher-order-mapping/
For example:
refreshSSO(): Observable<boolean> {
const refresh_uri = <sso endpoint>;
const config = matDialogHelpers.getDefaultConfig({});
const matDialogRef: MatDialogRef<LaunchRefreshComponent> = this.matDialog.open(LaunchRefreshComponent, config);
return matDialogRef.afterClosed().pipe(
mergeMap(
next => {
if (next === 'launch') {
return this.popupAuth(refresh_uri); // This might not complete, unless you take care of it. Look into take/takeUntil/takeWhile operators.
} else {
return of(false); // This one will complete immediately.
}
})
);
}
Remember to complete or unsubscribe from the Observable to prevent leaks.
For example:
const subscription = this.refreshSSO().subscribe((value) => {
if(value == isWhatNeeded) {
subscription.unsubscribe();
}
});
Upvotes: 2