Improve Entra account and token resolution performance - #22615
Conversation
There was a problem hiding this comment.
Pull request overview
This PR optimizes Entra-backed authentication flows by reducing avoidable VS Code authentication-provider work during connection setup and token acquisition, primarily by deferring tenant enumeration and improving account/tenant resolution behavior.
Changes:
- Avoid eager tenant enumeration when listing VS Code accounts and when initializing the connection dialog.
- Improve account ID/label resolution (case-insensitive + legacy-compatible IDs).
- Use an explicitly selected tenant without re-enumerating tenants, and add/update unit tests for these behaviors.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| extensions/mssql/src/azure/vscodeEntraMfaUtils.ts | Updates Entra account normalization and token acquisition flow to avoid unnecessary tenant enumeration. |
| extensions/mssql/src/connectionconfig/azureHelpers.ts | Adjusts VS Code account lookup call sites to avoid tenant-filtering work when not needed. |
| extensions/mssql/src/connectionconfig/connectionDialogWebviewController.ts | Removes background preloading of tenants and avoids tenant enumeration when loading VS Code accounts. |
| extensions/mssql/test/unit/vscodeEntraMfaUtils.test.ts | Adds coverage for account options retrieval and token acquisition without tenant enumeration. |
| extensions/mssql/test/unit/connectionDialogWebviewController.test.ts | Adds a regression test ensuring tenants aren’t loaded for every account in the background. |
| extensions/mssql/test/unit/azureHelpers.test.ts | Updates expectations for the new getAccounts(false) usage. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (4)
extensions/mssql/test/unit/vscodeEntraMfaUtils.test.ts:101
- Avoid using exact call-count assertions (like
calledOnceWith) here; they’re brittle and make the test fail on unrelated refactors. Prefer asserting on the call arguments only.
expect(getTenantsForAccount).to.have.been.calledOnceWith(mockAccounts.signedInAccount);
extensions/mssql/src/azure/vscodeEntraMfaUtils.ts:124
tenantIdis now trimmed for tenant resolution, but both error paths still pass the raw (possibly whitespace/padded)tenantIdinto the localized message. That can produce confusing messages that include extra whitespace. Consider trimming/normalizing the tenant ID before passing it toaccountNotAvailableThroughVsCode.
let resolvedTenantId = tenantId?.trim() || undefined;
if (!resolvedTenantId) {
const tenants = await VsCodeAzureHelper.getTenantsForAccount(account);
resolvedTenantId = getDefaultTenantId(account.id, tenants);
}
extensions/mssql/src/connectionconfig/azureHelpers.ts:163
getAccountByIdis typed to always return an account, butArray.prototype.findcan returnundefined. This can lead to runtime errors in callers that assume a value is always returned. Consider returningPromise<… | undefined>and handling the missing-account case at call sites, or throw a clear error here.
accountId: string,
): Promise<vscode.AuthenticationSessionAccountInformation> {
const accounts = await this.getAccounts(false);
return accounts.find((a) => a.id === accountId);
}
extensions/mssql/src/connectionconfig/azureHelpers.ts:170
getAccountByNamehas the same contract issue asgetAccountById:.find(...)may returnundefined, but the return type is non-optional. Align the signature/behavior to avoid surprising runtime failures.
accountName: string,
): Promise<vscode.AuthenticationSessionAccountInformation> {
const accounts = await this.getAccounts(false);
return accounts.find((a) => a.label === accountName);
}
|
Tested these changes against Azure SQL DBs and a Dataverse database, working well. I also did some quick perf benchmarking, and found that these changes speed up an initial connection using Entra auth by about 60%. Thanks for this PR, Chris Johnstone (@cjohnsto-nz)! |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (4)
extensions/mssql/src/connectionconfig/connectionDialogWebviewController.ts:268
- Typo in comment: "intitial" should be "initial".
// Display intitial UI since it may take a moment for the connection to load
// due to fetching Azure account info
extensions/mssql/test/unit/connectionDialogWebviewController.test.ts:1029
- This test calls a public method via bracket notation, which bypasses type checking and is less maintainable. Since loadVscodeEntraDataAsync is public, call it directly.
await controller["loadVscodeEntraDataAsync"]();
extensions/mssql/src/azure/vscodeEntraMfaUtils.ts:37
- The new behavior normalizes IDs to lowercase for case-insensitive compatibility, but there isn't a unit test covering mixed-case inputs. Adding a test would prevent regressions (e.g., "User@Example.com" vs "user@example.com").
const normalizedCurrentAccountId = currentAccountId?.toLowerCase();
const normalizedExpectedAccountId = expectedAccountId?.toLowerCase();
return (
!!normalizedCurrentAccountId &&
!!normalizedExpectedAccountId &&
(normalizedCurrentAccountId === normalizedExpectedAccountId ||
normalizedCurrentAccountId.startsWith(normalizedExpectedAccountId) ||
normalizedExpectedAccountId.startsWith(normalizedCurrentAccountId))
extensions/mssql/test/unit/vscodeEntraMfaUtils.test.ts:102
- Avoid brittle call-count assertions like calledOnceWith here; it tends to break on harmless refactors. It's usually enough to assert the important argument(s) were used.
expect(result.tenantId).to.equal(expectedTenantId);
expect(getTenantsForAccount).to.have.been.calledOnceWith(mockAccounts.signedInAccount);
});
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (4)
extensions/mssql/src/connectionconfig/azureHelpers.ts:169
getAccountByNamecan returnundefinedwhen the requested account label isn’t present, but the return type claims it always returns an account. Returningundefinedhere can lead to downstream runtime errors; consider throwing when no match is found (or otherwise never returnundefined).
const accounts = await this.getAccounts(false);
return accounts.find((a) => a.label === accountName);
extensions/mssql/src/connectionconfig/azureHelpers.ts:162
getAccountByIdcan returnundefinedwhen the requested account ID isn’t present, but the return type claims it always returns an account. Several callers immediately access.label/ pass the result to tenant APIs, which can crash at runtime if the account disappears or is unavailable. Consider throwing a clear error when the account can’t be resolved (or otherwise never returnundefinedfrom this method).
This issue also appears on line 168 of the same file.
const accounts = await this.getAccounts(false);
return accounts.find((a) => a.id === accountId);
extensions/mssql/test/unit/vscodeEntraMfaUtils.test.ts:101
- This assertion depends on an exact call count via
calledOnceWith, which is brittle (incidental extra calls will break the test). Prefer asserting on parameters without a specific count (e.g.calledWith/calledWithMatch).
expect(getTenantsForAccount).to.have.been.calledOnceWith(mockAccounts.signedInAccount);
extensions/mssql/src/connectionconfig/connectionDialogWebviewController.ts:268
- Typo in comment: “intitial” should be “initial”.
// Display intitial UI since it may take a moment for the connection to load
// due to fetching Azure account info
ffbb33a
into
microsoft:main
* Optimize Entra account and token resolution * Address Entra review feedback * fixing lint error --------- Co-authored-by: Benjin Dubishar <benjin.dubishar@gmail.com>
|
Thanks Benjin Dubishar (@Benjin). I think there is still some room for improvement in the Connection Dialog too, but I'll tackle that another time 🙂 |
|
Chris Johnstone (@cjohnsto-nz) feel free to file some bugs/tasks with the improvements you have in mind so they don't fall through the cracks! |
Description
This PR extracts the Entra authentication improvements from #22614 into a focused change.
It reduces avoidable work during Entra-backed connection setup by:
These changes make Entra-backed connections faster and reduce unnecessary authentication-provider calls while preserving the existing interactive sign-in fallback.
Validation performed:
npm run build -- --target mssqlnpm run test -- --target mssql --coverage=falsenpm run package -- --target mssql --onlineCode Changes Checklist
npm run test)Reviewers: Please read our reviewer guidelines
Bug: #22706