Skip to content
Merged
Show file tree
Hide file tree
Changes from 86 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
09b7250
Add changes for resources-api
MicroFish91 Nov 4, 2025
37147d3
Add changes to Azure Resources
MicroFish91 Nov 4, 2025
9920f41
Add todo
MicroFish91 Nov 4, 2025
611ab51
Some nits
MicroFish91 Nov 4, 2025
2f5d146
Misc changes
MicroFish91 Nov 6, 2025
bb212ab
Update error messages and readme
MicroFish91 Nov 6, 2025
a8d2e09
More updates to readme
MicroFish91 Nov 6, 2025
39e1b69
Update getAzureResourcesApi function signature
MicroFish91 Nov 6, 2025
18dce26
Void
MicroFish91 Nov 6, 2025
7d1dfdc
Clean up names some more
MicroFish91 Nov 6, 2025
f45cf0d
More updates to documentation
MicroFish91 Nov 6, 2025
3e80d80
Add logic for allowed extension ids
MicroFish91 Nov 6, 2025
183e4dc
Add important note
MicroFish91 Nov 6, 2025
79b7421
Use a set
MicroFish91 Nov 7, 2025
7dc9819
Simplify auth readme
MicroFish91 Nov 7, 2025
0b31112
WIP
MicroFish91 Nov 10, 2025
e1caffc
Revert package.json and package-lock.json
MicroFish91 Nov 10, 2025
1f5b406
Update api type def file
MicroFish91 Nov 10, 2025
b9af84e
Add azure tools publisher constant
MicroFish91 Nov 11, 2025
71f4f14
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 11, 2025
f188eca
Add auth tests and supporting logic
MicroFish91 Nov 11, 2025
e71785c
Update with better comments
MicroFish91 Nov 12, 2025
3f4cb3a
Revert launch change
MicroFish91 Nov 12, 2025
34d2f1a
Use extensionId var
MicroFish91 Nov 12, 2025
c34d952
Add note
MicroFish91 Nov 12, 2025
8079638
Update types, errors, and comments
MicroFish91 Nov 12, 2025
dbba10e
Update typings
MicroFish91 Nov 12, 2025
29e7976
Update comments
MicroFish91 Nov 12, 2025
5b0d57a
Merge with parent branch
MicroFish91 Nov 12, 2025
fa07ab1
Use an enum for error codes
MicroFish91 Nov 13, 2025
4e9e686
Update readme and comments
MicroFish91 Nov 13, 2025
4c49c09
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 13, 2025
0b1d03e
Update mock credential manager
MicroFish91 Nov 13, 2025
cb7b973
Update a comment
MicroFish91 Nov 13, 2025
570ecf4
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 13, 2025
03da414
Update enum formatting
MicroFish91 Nov 13, 2025
b446718
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 13, 2025
11d1ffa
Fix a typo
MicroFish91 Nov 13, 2025
0a7b447
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 13, 2025
4140cbf
Change comment casing
MicroFish91 Nov 13, 2025
3cf4fa3
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 13, 2025
69051c0
Remove part of a comment
MicroFish91 Nov 14, 2025
d178910
Update file structure, add capability for custom dependency injection
MicroFish91 Nov 19, 2025
a816d08
Remove a comment
MicroFish91 Nov 19, 2025
e433035
Merge with main + some new changes
MicroFish91 Nov 19, 2025
1718244
Fix formatting
MicroFish91 Nov 19, 2025
bb725ac
Add client related tests
MicroFish91 Nov 19, 2025
9ab914a
Fix some variable names
MicroFish91 Nov 19, 2025
06e2b99
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 19, 2025
d0eab17
Merge branch 'mwf/v4-tests' of https://github.com/microsoft/vscode-az…
MicroFish91 Nov 19, 2025
ef7ad23
Match to equal
MicroFish91 Nov 19, 2025
fb297bd
Merge branch 'mwf/v4-tests' of https://github.com/microsoft/vscode-az…
MicroFish91 Nov 19, 2025
0e438fa
semicolons
MicroFish91 Nov 19, 2025
97b1239
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 19, 2025
f22c0dc
Merge branch 'mwf/v4-tests' of https://github.com/microsoft/vscode-az…
MicroFish91 Nov 19, 2025
eda6ce6
Escape the symbol
MicroFish91 Nov 19, 2025
18db77c
Merge branch 'mwf/v4-tests' of https://github.com/microsoft/vscode-az…
MicroFish91 Nov 19, 2025
90fe885
Escape the symbol
MicroFish91 Nov 19, 2025
dbc30e6
Update a comment
MicroFish91 Nov 19, 2025
50026aa
Update another comment
MicroFish91 Nov 19, 2025
1c6db3b
Move client tools changes
MicroFish91 Nov 20, 2025
1f2bbf0
Add back in client tooling
MicroFish91 Nov 20, 2025
b5eb5f9
Merge branch 'mwf/v4-client-tools' of https://github.com/microsoft/vs…
MicroFish91 Nov 20, 2025
1b7eef5
Merge branch 'mwf/v4-tests' of https://github.com/microsoft/vscode-az…
MicroFish91 Nov 20, 2025
5a1ad77
Add back in some missing files that were moved
MicroFish91 Nov 20, 2025
b542c30
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 20, 2025
bf36371
Merge with main
MicroFish91 Nov 20, 2025
2580b09
Remove a var
MicroFish91 Nov 20, 2025
c9ce482
Semicolon
MicroFish91 Nov 20, 2025
54299f9
Preserve merge formatting
MicroFish91 Nov 20, 2025
16ba61a
Fix lint warning
MicroFish91 Nov 20, 2025
97bc6e8
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 20, 2025
81ce320
Merge with new eng package changes
MicroFish91 Nov 20, 2025
5c11b97
Inject more extension vars
MicroFish91 Nov 20, 2025
08b7d94
Revert unnecessary formats
MicroFish91 Nov 20, 2025
3817e17
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 20, 2025
ff9d912
Merge branch 'mwf/v4-client-tools' of https://github.com/microsoft/vs…
MicroFish91 Nov 20, 2025
6174219
Merge branch 'main' of https://github.com/microsoft/vscode-azureresou…
MicroFish91 Nov 21, 2025
f7f5026
Merge branch 'mwf/v4' of https://github.com/microsoft/vscode-azureres…
MicroFish91 Nov 21, 2025
1e9269d
Merge with main + add getUI
MicroFish91 Nov 21, 2025
8edafe9
Add type
MicroFish91 Nov 21, 2025
7807894
Merge with mwf/v4-tests
MicroFish91 Nov 21, 2025
62c9615
Remove extension bundle references
MicroFish91 Nov 21, 2025
5d0e4ad
Fix lint warning
MicroFish91 Nov 21, 2025
0d63c1c
Add an extra test
MicroFish91 Nov 21, 2025
20380f4
Merge branch 'mwf/v4-tests' of https://github.com/microsoft/vscode-az…
MicroFish91 Nov 21, 2025
475dfb0
Lint stuff
MicroFish91 Dec 4, 2025
3051f28
Merge with main
MicroFish91 Jan 27, 2026
398227e
Fix merge
MicroFish91 Jan 27, 2026
27c1f63
newline
MicroFish91 Jan 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
"preLaunchTask": "Watch: ESBuild",
"env": {
"DEBUGTELEMETRY": "v",
"AzCode_EnableLongRunningTestsLocal": ""
"AzCode_EnableLongRunningTestsLocal": "",
"VSCODE_RUNNING_TESTS": "true",
}
},
]
Expand Down
12 changes: 2 additions & 10 deletions api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,16 +221,8 @@ This extension declares that it registers a BranchDataProvider for the `Function

## Getting started

On activation, client extensions can fetch an instance of the Azure Resources API using the `getAzureResourcesExtensionApi` utility provided by the [`@microsoft/vscode-azureresources-api`](https://www.npmjs.com/package/@microsoft/vscode-azureresources-api) package.

```ts
import { getAzureResourcesExtensionApi } from '@microsoft/vscode-azureresources-api';

export async function activate(context: vscode.ExtensionContext): Promise<void> {
const azureResourcesApi = await getAzureResourcesExtensionApi(context, '2.0.0');
// ...register providers
}
```
On activation, client extensions can fetch an instance of the Azure Resources API using utilities provided by the [`@microsoft/vscode-azureresources-api`](https://www.npmjs.com/package/@microsoft/vscode-azureresources-api) package.
A guide on fetching the API through the Azure Resources authentication layer can be found [here](https://github.com/microsoft/vscode-azureresourcegroups/blob/main/api/src/auth/README.md).

<!-- ## Contribute to the Azure resources view

Expand Down
Binary file added api/docs/media/api-request-handshake.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
113 changes: 108 additions & 5 deletions api/docs/vscode-azureresources-api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export declare namespace apiUtils {
*/
export function getAzureExtensionApi<T extends AzureExtensionApi>(context: vscode.ExtensionContext, extensionId: string, apiVersionRange: string, options?: GetApiOptions): Promise<T>;
/**
* Get extension exports for the extension with the given id. Activates extension first if needed.
* Activates an extension and returns its exports.
*
* @returns `undefined` if the extension is not installed
*/
Expand Down Expand Up @@ -124,19 +124,28 @@ export declare interface AzureAuthentication {
/**
* Gets a VS Code authentication session for an Azure subscription.
*
* @param scopes - The scopes for which the authentication is needed. Use AuthenticationWwwAuthenticateRequest for supporting challenge requests.
* Note: use of AuthenticationWwwAuthenticateRequest requires VS Code v1.104
* @param scopeListOrRequest - The scopes for which the authentication is needed. Use AuthenticationWwwAuthenticateRequest for supporting challenge requests.
* Note: use of AuthenticationWwwAuthenticateRequest requires VS Code v1.105.0
*
* @returns A VS Code authentication session or undefined, if none could be obtained.
*/
getSessionWithScopes(scopes: string[] | vscode.AuthenticationWwwAuthenticateRequest): vscode.ProviderResult<vscode.AuthenticationSession>;
getSessionWithScopes(scopeListOrRequest: string[] | vscode.AuthenticationWwwAuthenticateRequest): vscode.ProviderResult<vscode.AuthenticationSession>;
}

export declare interface AzureExtensionApi {
/**
* The API version for this extension. It should be versioned separately from the extension and ideally remains backwards compatible.
*/
apiVersion: string;
/**
* Optional endpoint which Azure client extensions should implement in order to receive an Azure Resources API session.
* See: https://github.com/microsoft/vscode-azureresourcegroups/blob/main/api/src/auth/README.md
*
* @param azureResourcesCredential - The credential to use when requesting the Azure Resources API
* @param clientCredential - The client verification credential initially generated by the client and passed to the Azure Resources API when requesting a new session.
* This credential is used to verify that the real Azure Resources extension is the one providing back the session credential.
*/
receiveAzureResourcesApiSession?(azureResourcesCredential: string, clientCredential: string): void | Promise<void>;
}

/**
Expand Down Expand Up @@ -202,13 +211,94 @@ export declare interface AzureResourceModel extends ResourceModelBase {
readonly viewProperties?: ViewPropertiesModel;
}

export declare interface AzureResourcesApiRequestContext {
clientExtensionId: string;
azureResourcesApiVersions: string[];
/**
* Callback invoked when Azure Resource APIs are successfully obtained through the authentication handshake.
*
* @param azureResourcesApis - Array of APIs corresponding to the requested versions. APIs are returned in the same
* order as provided in this request context. If a requested version is not
* available or does not match, `undefined` will be returned at that position.
*/
onDidReceiveAzureResourcesApis: (azureResourcesApis: (AzureResourcesExtensionApi | AzureExtensionApi | undefined)[]) => void | Promise<void>;
/**
* Optional callback invoked when an error occurs during the Azure Resources API handshake process.
*
* @remarks Errors thrown during execution of this callback may be part of a separate process and may not bubble up to users.
* If you wish to surface specific errors to users, please consider logging them or using the VS Code API to display them through UI.
*
* @param error - The error that occurred during the handshake, containing an error code and message.
*/
onApiRequestError?: (error: AzureResourcesApiRequestError) => void | Promise<void>;
}

export declare type AzureResourcesApiRequestError = {
code: AzureResourcesApiRequestErrorCode;
message: string;
};

/**
* Codes for errors that could appear during the API request handshake between client extension and Azure Resources host extension.
*/
export declare enum AzureResourcesApiRequestErrorCode {
/**
* An error occurred while the client extension was creating its verification credential for the Azure Resources host extension.
*/
ClientFailedCreateCredential = "ERR_CLIENT_FAILED_CREATE_CREDENTIAL",
/**
* An error occurred while the Azure Resources host extension was trying to create an API session.
*/
HostCreateSessionFailed = "ERR_HOST_CREATE_SESSION_FAILED",
/**
* An error occurred because the client's receiver method was provided incomplete or missing credentials.
*/
ClientReceivedInsufficientCredentials = "ERR_CLIENT_RECEIVED_INSUFFICIENT_CREDENTIALS",
/**
* The client's receiver method was provided a client credential that failed verification.
*
* This may occur when:
* - An untrusted extension pretends to be the Azure Resources host extension and tries to pass a fake credential
* - There is a faulty behavior in the client's verification process
*/
ClientCredentialFailedVerification = "ERR_CLIENT_CREDENTIAL_FAILED_VERIFICATION",
/**
* An error occurred while asking the Azure Resources host extension to provision the specified APIs.
*
* This may occur when:
* - The Azure Resources extension cannot verify the issued credential that was passed back
* - The requesting extension is not on the Azure Resources allow list
* - The host extension encounters an internal error during API provisioning
*/
HostApiProvisioningFailed = "ERR_HOST_API_PROVISIONING_FAILED"
}

export declare type AzureResourcesApiRequestPrep<T extends AzureExtensionApi> = {
/**
* The modified client extension API. Ensures the required handshake receiver method has been added.
*/
clientApi: T & Required<Pick<T, 'receiveAzureResourcesApiSession'>>;
/**
* Initiates the authentication handshake required to obtain the Azure Resources API.
*/
requestResourcesApis: () => void;
};

/**
* The current (v2) Azure Resources extension API.
*/
export declare interface AzureResourcesExtensionApi extends AzureExtensionApi {
export declare interface AzureResourcesExtensionApi extends Omit<AzureExtensionApi, 'receiveAzureResourcesApiSession'> {
resources: ResourcesApi;
}

/**
* The authentication layer (v4) protecting the core Azure Resources extension API.
*/
export declare interface AzureResourcesExtensionAuthApi extends Omit<AzureExtensionApi, 'receiveAzureResourcesApiSession'> {
getAzureResourcesApis(clientExtensionId: string, azureResourcesCredential: string, azureResourcesApiVersions: string[]): Promise<(AzureExtensionApi | undefined)[]>;
createAzureResourcesApiSession(clientExtensionId: string, clientExtensionVersion: string, clientExtensionCredential: string): Promise<void>;
}

/**
* Represents a type of resource as designated by Azure.
*/
Expand Down Expand Up @@ -300,10 +390,23 @@ export declare function getAzExtResourceType(resource: {
kind?: string;
}): AzExtResourceType | undefined;

/**
* @deprecated The Azure Resources core API should be accessed through the new auth layer.
* See: https://github.com/microsoft/vscode-azureresourcegroups/blob/main/api/src/auth/README.md
* */
export declare function getAzureResourcesExtensionApi(extensionContext: vscode.ExtensionContext, apiVersionRange: '2.0.0', options?: GetApiOptions): Promise<AzureResourcesExtensionApi>;

export declare function isWrapper(maybeWrapper: unknown): maybeWrapper is Wrapper;

/**
* Prepares a client extension for the Azure Resources authentication handshake.
*
* @param context - Prerequisite configuration and handlers to prepare the request
* @param clientExtensionApi - The base extension API to be modified
* @returns The modified client extension API (with the required receiver method added), and a method to initiate the handshake
*/
export declare function prepareAzureResourcesApiRequest<T extends AzureExtensionApi>(context: AzureResourcesApiRequestContext, clientExtensionApi: T): AzureResourcesApiRequestPrep<T>;

/**
* Represents the base type for all Azure and workspace resources.
*/
Expand Down
85 changes: 85 additions & 0 deletions api/src/auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Azure Resources Authentication and API Retrieval

This guide covers the Azure Resources authentication handshake required for API retrieval by client extensions. It also provides information on the tools available to help client extensions quickly onboard to the new flow.

## The Authentication Handshake

### Overview

Azure Resources APIs are protected behind the new v4 authentication layer. This layer exposes two methods that client extensions must use to gain access: `createAzureResourcesApiSession` and `getAzureResourcesApis`. During activation, client extensions are expected to export an API including a receiver method called `receiveAzureResourcesApiSession` before initiating the API request handshake.

### Steps

1. On activation, the client extension should export its API and initiate the handshake by calling `createAzureResourcesApiSession`. The client extension should provide its own verification credential as part of this request (more on this later).

1. The Azure Resources host extension verifies that the requesting extension is on its approved list. If approved, Azure Resources does not respond directly. Instead, it retrieves the extension's API from VS Code directly using the approved extension ID, then delivers the session credential via the `receiveAzureResourcesApiSession` receiver method. This ensures the credential reaches the approved recipient, even if a malicious actor tried to initiate the request. Azure Resources also returns the original client credential so the client extension can verify that it is communicating with the genuine Azure Resources extension.

1. The client extension should then use the Azure Resources credential to retrieve the Azure Resources APIs by calling `getAzureResourcesApis`.

### Diagram
![Azure Resources API Request Handshake](https://github.com/microsoft/vscode-azureresourcegroups/blob/main/api/docs/media/api-request-handshake.png)

## Automating the Handshake

To simplify the handshake process, the following tools are made available and outlined below.

### The API Request

Create your extension's API (`AzureExtensionApi`) and pass it along with the requisite request context (`AzureResourcesApiRequestContext`). We'll explore how to populate this context in the section that follows.

The `prepareAzureResourcesApiRequest` tool that we provide performs two key operations:

1. **Prepares client extension API** - Returns your modified client extension API with the required `receiveAzureResourcesApiSession` receiver method added.
2. **Provides handshake initializer** - Returns a function that initiates the Resources API request handshake when called. Call this before exporting your API during extension activation.

```ts
const containerAppsApi: AzureExtensionApi = {
apiVersion: '1.0.0',
};

const { clientApi, requestResourcesApis } = prepareAzureResourcesApiRequest(context, containerAppsApi);
requestResourcesApis();
return createApiProvider([clientApi]);
```

### The API Request Context

The following example shows how to configure the context when preparing for an Azure Resources API handshake request.

```ts
const v2: string = '^2.0.0';

const context: AzureResourcesApiRequestContext = {
azureResourcesApiVersions: [v2],
clientExtensionId: 'ms-azuretools.vscode-azurecontainerapps',

// Successful retrieval of Azure Resources APIs will be returned here
onDidReceiveAzureResourcesApis: (azureResourcesApis: (AzureResourcesExtensionApi | undefined)[]) => {
const [rgApiV2] = azureResourcesApis;
if (!rgApiV2) {
throw new Error(l10n.t('Failed to find a matching Azure Resources API for version "{0}".', v2));
}
ext.rgApiV2 = rgApiV2;
ext.rgApiV2.resources.registerAzureResourceBranchDataProvider(AzExtResourceType.ContainerAppsEnvironment, ext.branchDataProvider);
},

// OPTIONAL: Can use for special error handling & telemetry
// NOTE: Errors thrown during execution of this callback may be part of a separate process and may not bubble up to users.
// If you wish to surface specific errors to users, please consider logging them or using the VS Code API to display them through UI.
onApiRequestError: async (error: AzureResourcesApiRequestError) => {
switch (true) {
case error.code === AzureResourcesApiRequestErrorCode.ClientFailedCreateCredential:
case error.code === AzureResourcesApiRequestErrorCode.HostCreateSessionFailed:
case error.code === AzureResourcesApiRequestErrorCode.ClientReceivedInsufficientCredentials:
case error.code === AzureResourcesApiRequestErrorCode.ClientCredentialFailedVerification:
case error.code === AzureResourcesApiRequestErrorCode.HostApiProvisioningFailed:
default:
}
},

};
```

---

[Back to README](https://github.com/microsoft/vscode-azureresourcegroups/blob/main/api/README.md)
49 changes: 49 additions & 0 deletions api/src/auth/apiRequest/AzureResourcesApiRequestContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AzureResourcesExtensionApi, AzureResourcesExtensionAuthApi } from "../../extensionApi";
import { AzureExtensionApi } from "../../utils/apiUtils";
import { AzExtCredentialManager } from "../credentialManager/AzExtCredentialManager";
import { AzureResourcesApiRequestError } from "./apiRequestErrors";

export interface AzureResourcesApiRequestContext {
clientExtensionId: string;
azureResourcesApiVersions: string[];

/**
* Callback invoked when Azure Resource APIs are successfully obtained through the authentication handshake.
*
* @param azureResourcesApis - Array of APIs corresponding to the requested versions. APIs are returned in the same
* order as provided in this request context. If a requested version is not
* available or does not match, `undefined` will be returned at that position.
*/
onDidReceiveAzureResourcesApis: (azureResourcesApis: (AzureResourcesExtensionApi | AzureExtensionApi | undefined)[]) => void | Promise<void>;

/**
* Optional callback invoked when an error occurs during the Azure Resources API handshake process.
*
* @remarks Errors thrown during execution of this callback may be part of a separate process and may not bubble up to users.
* If you wish to surface specific errors to users, please consider logging them or using the VS Code API to display them through UI.
*
* @param error - The error that occurred during the handshake, containing an error code and message.
*/
onApiRequestError?: (error: AzureResourcesApiRequestError) => void | Promise<void>;
}

// NOTE: Dependency injection options for tests; skip publically exporting this in the index
export interface CustomRequestDependenciesContext extends AzureResourcesApiRequestContext {
/**
* An optional credential manager used for issuing and verifying the client extensions credentials. If none are supplied, a simple UUID credential manager is used.
* @test Use this to more easily mock and inspect the behavior of the underlying credential manager.
*/
credentialManager?: AzExtCredentialManager;

/**
* An optional API provider to be used in lieu of the VS Code extension provider `vscode.extension.getExtension()`.
* This should _NOT_ be used in production environments.
* @test Use this to more easily mock and inject custom host extension API exports.
*/
hostApiProvider?: { getApi(): AzureResourcesExtensionAuthApi };
}
Loading