mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-26 11:38:51 +01:00
Bring back refresher (#229246)
Now we will refresh tokens over time so extensions can cache auth sessions in memory and just need to listen to the event to decide when to refresh their caches.
This commit is contained in:
committed by
GitHub
parent
41179f4908
commit
3b1cb3b155
@@ -5,7 +5,7 @@
|
||||
|
||||
import { PublicClientApplication, AccountInfo, Configuration, SilentFlowRequest, AuthenticationResult, InteractiveRequest, LogLevel } from '@azure/msal-node';
|
||||
import { Disposable, Memento, SecretStorage, LogOutputChannel, window, ProgressLocation, l10n, EventEmitter } from 'vscode';
|
||||
import { raceCancellationAndTimeoutError } from '../common/async';
|
||||
import { Delayer, raceCancellationAndTimeoutError } from '../common/async';
|
||||
import { SecretStorageCachePlugin } from '../common/cachePlugin';
|
||||
import { MsalLoggerOptions } from '../common/loggerOptions';
|
||||
import { ICachedPublicClientApplication } from '../common/publicClientCache';
|
||||
@@ -13,6 +13,7 @@ import { ICachedPublicClientApplication } from '../common/publicClientCache';
|
||||
export class CachedPublicClientApplication implements ICachedPublicClientApplication {
|
||||
private _pca: PublicClientApplication;
|
||||
private _sequencer = new Sequencer();
|
||||
private readonly _refreshDelayer = new DelayerByKey<AuthenticationResult>();
|
||||
|
||||
private _accounts: AccountInfo[] = [];
|
||||
private readonly _disposable: Disposable;
|
||||
@@ -89,6 +90,7 @@ export class CachedPublicClientApplication implements ICachedPublicClientApplica
|
||||
this._logger.debug(`[acquireTokenSilent] [${this._clientId}] [${this._authority}] [${request.scopes.join(' ')}] [${request.account.username}] got result`);
|
||||
if (result.account && !result.fromCache) {
|
||||
this._logger.debug(`[acquireTokenSilent] [${this._clientId}] [${this._authority}] [${request.scopes.join(' ')}] [${request.account.username}] firing event due to change`);
|
||||
this._setupRefresh(result);
|
||||
this._onDidAccountsChangeEmitter.fire({ added: [], changed: [result.account], deleted: [] });
|
||||
}
|
||||
return result;
|
||||
@@ -96,7 +98,7 @@ export class CachedPublicClientApplication implements ICachedPublicClientApplica
|
||||
|
||||
async acquireTokenInteractive(request: InteractiveRequest): Promise<AuthenticationResult> {
|
||||
this._logger.debug(`[acquireTokenInteractive] [${this._clientId}] [${this._authority}] [${request.scopes?.join(' ')}] loopbackClientOverride: ${request.loopbackClient ? 'true' : 'false'}`);
|
||||
return await window.withProgress(
|
||||
const result = await window.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
cancellable: true,
|
||||
@@ -108,6 +110,8 @@ export class CachedPublicClientApplication implements ICachedPublicClientApplica
|
||||
1000 * 60 * 5
|
||||
)
|
||||
);
|
||||
this._setupRefresh(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
removeAccount(account: AccountInfo): Promise<void> {
|
||||
@@ -149,6 +153,25 @@ export class CachedPublicClientApplication implements ICachedPublicClientApplica
|
||||
}
|
||||
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update complete`);
|
||||
}
|
||||
|
||||
private _setupRefresh(result: AuthenticationResult) {
|
||||
const on = result.refreshOn || result.expiresOn;
|
||||
if (!result.account || !on) {
|
||||
return;
|
||||
}
|
||||
|
||||
const account = result.account;
|
||||
const scopes = result.scopes;
|
||||
const timeToRefresh = on.getTime() - Date.now() - 5 * 60 * 1000; // 5 minutes before expiry
|
||||
const key = JSON.stringify({ accountId: account.homeAccountId, scopes });
|
||||
this._logger.debug(`[_setupRefresh] [${this._clientId}] [${this._authority}] [${scopes.join(' ')}] [${account.username}] timeToRefresh: ${timeToRefresh}`);
|
||||
this._refreshDelayer.trigger(
|
||||
key,
|
||||
// This may need the redirectUri when we switch to the broker
|
||||
() => this.acquireTokenSilent({ account, scopes, redirectUri: undefined, forceRefresh: true }),
|
||||
timeToRefresh > 0 ? timeToRefresh : 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Sequencer {
|
||||
@@ -159,3 +182,17 @@ export class Sequencer {
|
||||
return this.current = this.current.then(() => promiseTask(), () => promiseTask());
|
||||
}
|
||||
}
|
||||
|
||||
class DelayerByKey<T> {
|
||||
private _delayers = new Map<string, Delayer<T>>();
|
||||
|
||||
trigger(key: string, fn: () => Promise<T>, delay: number): Promise<T> {
|
||||
let delayer = this._delayers.get(key);
|
||||
if (!delayer) {
|
||||
delayer = new Delayer<T>(delay);
|
||||
this._delayers.set(key, delayer);
|
||||
}
|
||||
|
||||
return delayer.trigger(fn, delay);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user