-
Notifications
You must be signed in to change notification settings - Fork 47
Add an Azure Resources API (v4) authentication layer #1284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
||
| const v4: string = '4.0.0'; | ||
|
|
||
| export type AuthApiFactoryDependencies = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this type in preparation to leverage dependency injection during tests. It probably belongs in the follow-up test PR, but I'm hoping to not have to extract and re-add it again 😅
|
We need to write some documentation on how this new layer works. I'd like to help out writing the docs if you want my help, can you post the diagram you made @MicroFish91? |
Yup! I actually already have some docs and diagrams added in this other PR. Let me know if you think anything else should be added / changed to either the main README or the auth one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a new authentication layer (v4) for the Azure Resources API, implementing a secure handshake mechanism for client extensions to access core Azure Resources APIs. The auth layer uses credential-based verification to ensure only authorized extensions can access the protected APIs.
Changes:
- Added new v4 authentication API with session creation and verification
- Implemented UUID-based credential manager for secure token generation and validation
- Updated extension metadata to include publisher information for allowed extension list
- Deprecated direct access to core APIs in favor of authenticated access
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
src/api/auth/createAuthApiFactory.ts |
Creates the v4 auth API factory with session management |
src/api/auth/createApiSession/createApiSessionInternal.ts |
Handles session creation with extension whitelist validation |
src/api/auth/createApiSession/CreateApiSessionInternalContext.ts |
Context interface for session creation |
src/api/auth/verifyApiSession/verifyApiSessionInternal.ts |
Validates credentials during API access |
src/api/auth/verifyApiSession/VerifyApiSessionInternalContext.ts |
Context interface for verification |
api/src/auth/credentialManager/AzExtCredentialManager.ts |
Interface for credential management |
api/src/auth/credentialManager/AzExtUUIDCredentialManager.ts |
UUID-based credential manager implementation |
api/src/extensionApi.ts |
Adds new auth API interface definitions |
api/src/utils/apiUtils.ts |
Adds optional receiveAzureResourcesApiSession method and refactors getExtensionExports |
api/src/utils/getApi.ts |
Adds deprecation notice for direct API access |
api/src/utils/maskValue.ts |
Utility for masking sensitive credential values |
src/extension.ts |
Integrates auth factory into API provider structure |
src/azureExtensions.ts |
Adds publisher field to all extension metadata for allowlist |
src/hostapi.v4.internal.ts |
Type export for internal v4 auth API |
src/hostapi.v2.internal.ts |
Adds copyright header |
Comments suppressed due to low confidence (1)
src/azureExtensions.ts:155
- There are two entries in the
azureExtensionsarray for 'vscode-azureresourcegroups' (lines 64-69 for "Resource Groups" and lines 149-155 for "Managed Identity"). Since line 12 states these are "deduped and used to build the final list of allowed extensions", having duplicate extension names may cause confusion or unintended behavior. Consider consolidating these into a single entry with both labels or ensuring the deduplication logic handles this correctly.
name: 'vscode-azureresourcegroups',
publisher: msAzureToolsPublisher,
label: 'Managed Identity',
resourceTypes: [
AzExtResourceType.ManagedIdentityUserAssignedIdentities
]
},
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
api/src/utils/maskValue.ts
Outdated
| if (valueToMask) { | ||
| const formsOfValue: string[] = [valueToMask, encodeURIComponent(valueToMask)]; | ||
| for (const v of formsOfValue) { | ||
| data = data.replace(new RegExp(escape(v), 'gi'), '---'); |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The global escape function is deprecated and should not be used. Consider using a utility function from a well-maintained library (e.g., lodash.escapeRegExp) or implementing regex escaping manually by replacing special regex characters. For example: value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
| data = data.replace(new RegExp(escape(v), 'gi'), '---'); | |
| data = data.replace(new RegExp(v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi'), '---'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyone have thoughts on this? I can look into this more tomorrow, but I literally just copied the maskValue function that we use in utils. If it's worth changing here, it's probably also worth changing there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation uses the escape function when building a regular expression to mask sensitive values. However, escape only performs URI encoding and does not account for special regex characters like ., [], (), and others. As a result, if the value to mask contains any of these special characters, the regular expression may match unintended patterns or too broadly. For example, if valueToMask is alice@example.com, using escape(valueToMask) in the regex would also match and mask variations like alice@example-com, since the dot in the pattern is not escaped and matches any character.
I think we should go with Copilot's suggestion here. And also change the maskValue util.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR here: microsoft/vscode-azuretools#2170
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind, Copilot is wrong here. It didn't look that we're using this package: https://github.com/sindresorhus/escape-string-regexp and not the global escape function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait, it was correct. We are using the global escape here since when you copied over the code you didn't also copy over the import and now it's using global escape. Follow what I did here: microsoft/vscode-azuretools#2171
src/api/auth/createApiSession/CreateApiSessionInternalContext.ts
Outdated
Show resolved
Hide resolved
| await apiUtils.getAzureExtensionApi(ext.context, context.clientExtensionId, context.clientExtensionVersion); | ||
|
|
||
| const azureResourcesCredential: string = await context.credentialManager.createCredential(context.clientExtensionId); | ||
| await clientApi.receiveAzureResourcesApiSession?.(azureResourcesCredential, context.clientExtensionCredential); |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code uses optional chaining receiveAzureResourcesApiSession?.() which will silently do nothing if the method doesn't exist on the client API. However, this may be intentional to support backward compatibility with client extensions that haven't implemented this method yet. Consider adding telemetry to track whether clients are implementing this method to aid in the migration process.
| await clientApi.receiveAzureResourcesApiSession?.(azureResourcesCredential, context.clientExtensionCredential); | |
| const hasReceiveAzureResourcesApiSession: boolean = typeof (clientApi as any).receiveAzureResourcesApiSession === 'function'; | |
| context.telemetry.properties.clientHasReceiveAzureResourcesApiSession = String(hasReceiveAzureResourcesApiSession); | |
| if (hasReceiveAzureResourcesApiSession) { | |
| await (clientApi as any).receiveAzureResourcesApiSession(azureResourcesCredential, context.clientExtensionCredential); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I vote no on this one, client tooling should automatically handle setting all of this up anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be recording telemetry on extensions who haven't updated to use our new auth? Seems like a good way to help us track it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good idea, I'll add telemetry for that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve been thinking about this more, and I don’t think adding this specific piece of telemetry would give us the signal we’re looking for. Most existing client extensions aren’t routed through this auth layer yet, so this code path wouldn’t be triggered for them. Extensions that do migrate would likely use our client tooling, which would skew the data toward an apparent ~100% telemetry match for the receiver method.
Instead, it might be possible to infer this using the telemetry we already have. One option could be to look at which extensions are using the auth layer by examining the extensionIds recorded for these events:
-
api.getAzureResourcesApis -
api.createAzureResourcesApiSession
We could then compare that against the set of extensions calling into the core APIs, where extensionIds appear to be recorded here:

Let me know what you think / whether this approach could makes sense.
If this sounds reasonable, I can spend some time this afternoon double-checking whether this is feasible with the telemetry we already have wired up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome 🙂
I verified via query that we can see the calling extension IDs for core API methods already. I also double-checked that output telemetry for the new code paths being introduced here are logging the extensionIds, verified via the debug console showing output telemetry during the internal auth tests. At that point, I assume it should be straightforward enough to cross-reference the diffs to find any extensions that still need to migrate.
Overview
This PR adds a secure auth layer that clients should interface with to obtain the Azure Resources core APIs (used for registering branch data resources). For full details on the new auth handshake, please see the auth readme included with this PR. We will continue to publicly provide the core APIs while we let clients onboard. Afterwards we will remove these APIs from the public exports and only expose them through the dedicated auth layer.
Setup
Here are the steps if you would like to try out the changes:
npm install&npm run compilein Azure Resources rootnpm install&npm packin Azure Resources API rootnpm installand add the Azure Resources API package built from step 3onDidReceiveAzureResourcesApiscallback to verify we are getting matching Azure Resources APIsClient Extension Samples
Container Apps example (V2): microsoft/vscode-azurecontainerapps#992
Functions example (internal + V2): microsoft/vscode-azurefunctions#4777
Todos
To add in follow-up PRs.
UPDATE (11/20/2025):
I split up the PRs a bit better, now the client tooling lives in this PR. Therefore if you want to test the functionality described under
Setupabove, you'll now need to test off of that branch instead.The order of the PRs to review should be: