Skip to content

Commit 8789b28

Browse files
scottaddieCopilot
andauthored
Update Azure managed identity docs (#1712)
Convert language examples to tabs and refresh the managed identity guidance for Microsoft Foundry, including environment configuration, branding, and language-specific Azure Identity usage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9b3dadf commit 8789b28

1 file changed

Lines changed: 106 additions & 58 deletions

File tree

docs/setup/azure-managed-identity.md

Lines changed: 106 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,97 @@
11
# Azure managed identity with BYOK
22

3-
The Copilot SDK's [BYOK mode](../auth/byok.md) accepts static API keys, but Azure deployments often use **Managed Identity** (Entra ID) instead of long-lived keys. Since the SDK doesn't natively support Entra ID authentication, you can use a short-lived bearer token via the `bearer_token` provider config field.
3+
The Copilot SDK's [BYOK mode](../auth/byok.md) accepts static API keys, but Azure deployments often use **Managed Identity** (Microsoft Entra ID) instead of long-lived keys. Since the SDK doesn't natively support Microsoft Entra authentication, you can use a short-lived bearer token via the `bearer_token` provider config field.
44

5-
This guide shows how to use `DefaultAzureCredential` from the [Azure Identity](https://learn.microsoft.com/python/api/azure-identity/azure.identity.defaultazurecredential) library to authenticate with Azure AI Foundry models through the Copilot SDK.
5+
This guide shows how to use the Azure Identity SDK's `DefaultAzureCredential` API to authenticate with Microsoft Foundry models through the Copilot SDK.
66

77
## How it works
88

9-
Azure AI Foundry's OpenAI-compatible endpoint accepts bearer tokens from Entra ID in place of static API keys. The pattern is:
9+
Microsoft Foundry's OpenAI-compatible endpoint accepts bearer tokens from Microsoft Entra ID in place of static API keys. The pattern is:
1010

11-
1. Use `DefaultAzureCredential` to obtain a token for the `https://cognitiveservices.azure.com/.default` scope
11+
1. Use `DefaultAzureCredential` to obtain a token for the `https://ai.azure.com/.default` scope
1212
1. Pass the token as the `bearer_token` in the BYOK provider config
1313
1. Refresh the token before it expires (tokens are typically valid for ~1 hour)
1414

1515
```mermaid
1616
sequenceDiagram
1717
participant App as Your Application
18-
participant AAD as Entra ID
18+
participant MEID as Microsoft Entra ID
1919
participant SDK as Copilot SDK
20-
participant Foundry as Azure AI Foundry
20+
participant Foundry as Microsoft Foundry
2121
22-
App->>AAD: DefaultAzureCredential.get_token()
23-
AAD-->>App: Bearer token (~1hr)
22+
App->>MEID: DefaultAzureCredential.get_token()
23+
MEID-->>App: Bearer token (~1hr)
2424
App->>SDK: create_session(provider={bearer_token: token})
2525
SDK->>Foundry: Request with Authorization: Bearer <token>
2626
Foundry-->>SDK: Model response
2727
SDK-->>App: Session events
2828
```
2929

30-
## Python example
30+
## Code samples
31+
32+
<details open>
33+
<summary><strong>.NET</strong></summary>
34+
35+
### Prerequisites
36+
37+
Install the required packages:
38+
39+
```bash
40+
dotnet add package GitHub.Copilot.SDK
41+
dotnet add package Azure.Core
42+
```
43+
44+
### Basic usage
45+
46+
<!-- docs-validate: skip -->
47+
48+
```csharp
49+
using Azure.Core;
50+
using Azure.Identity;
51+
using GitHub.Copilot;
52+
53+
DefaultAzureCredential credential = new(
54+
DefaultAzureCredential.DefaultEnvironmentVariableName);
55+
AccessToken token = await credential.GetTokenAsync(
56+
new TokenRequestContext(new[] { "https://ai.azure.com/.default" }));
57+
58+
await using CopilotClient client = new();
59+
string? foundryUrl = Environment.GetEnvironmentVariable("FOUNDRY_RESOURCE_URL");
60+
61+
await using CopilotSession session = await client.CreateSessionAsync(new SessionConfig
62+
{
63+
Model = "gpt-5.5",
64+
Provider = new ProviderConfig
65+
{
66+
Type = "openai",
67+
BaseUrl = $"{foundryUrl!.TrimEnd('/')}/openai/v1/",
68+
BearerToken = token.Token,
69+
WireApi = "responses",
70+
},
71+
});
72+
73+
AssistantMessageEvent? response = await session.SendAndWaitAsync(
74+
new MessageOptions { Prompt = "Hello from Managed Identity!" });
75+
Console.WriteLine(response?.Data.Content);
76+
```
77+
78+
</details>
79+
80+
<details>
81+
<summary><strong>Python</strong></summary>
3182

3283
### Prerequisites
3384

85+
Install the required packages:
86+
3487
```bash
3588
pip install github-copilot-sdk azure-identity
3689
```
3790

3891
### Basic usage
3992

93+
<!-- docs-validate: skip -->
94+
4095
```python
4196
import asyncio
4297
import os
@@ -45,22 +100,22 @@ from azure.identity import DefaultAzureCredential
45100
from copilot import CopilotClient
46101
from copilot.session import PermissionHandler, ProviderConfig
47102

48-
COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default"
103+
SCOPE = "https://ai.azure.com/.default"
49104

50105

51106
async def main():
52107
# Get a token using Managed Identity, Azure CLI, or other credential chain
53-
credential = DefaultAzureCredential()
54-
token = credential.get_token(COGNITIVE_SERVICES_SCOPE).token
108+
credential = DefaultAzureCredential(require_envvar=True)
109+
token = credential.get_token(SCOPE).token
55110

56-
foundry_url = os.environ["AZURE_AI_FOUNDRY_RESOURCE_URL"]
111+
foundry_url = os.environ["FOUNDRY_RESOURCE_URL"]
57112

58113
client = CopilotClient()
59114
await client.start()
60115

61116
session = await client.create_session(
62117
on_permission_request=PermissionHandler.approve_all,
63-
model="gpt-4.1",
118+
model="gpt-5.5",
64119
provider=ProviderConfig(
65120
type="openai",
66121
base_url=f"{foundry_url.rstrip('/')}/openai/v1/",
@@ -82,26 +137,28 @@ asyncio.run(main())
82137

83138
Bearer tokens expire (typically after ~1 hour). For servers or long-running agents, refresh the token before creating each session:
84139

140+
<!-- docs-validate: skip -->
141+
85142
```python
86143
from azure.identity import DefaultAzureCredential
87144
from copilot import CopilotClient
88145
from copilot.session import PermissionHandler, ProviderConfig
89146

90-
COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default"
147+
SCOPE = "https://ai.azure.com/.default"
91148

92149

93150
class ManagedIdentityCopilotAgent:
94-
"""Copilot agent that refreshes Entra ID tokens for Azure AI Foundry."""
151+
"""Copilot agent that refreshes Microsoft Entra tokens for Microsoft Foundry."""
95152

96-
def __init__(self, foundry_url: str, model: str = "gpt-4.1"):
153+
def __init__(self, foundry_url: str, model: str = "gpt-5.5"):
97154
self.foundry_url = foundry_url.rstrip("/")
98155
self.model = model
99-
self.credential = DefaultAzureCredential()
156+
self.credential = DefaultAzureCredential(require_envvar=True)
100157
self.client = CopilotClient()
101158

102159
def _get_provider_config(self) -> ProviderConfig:
103160
"""Build a ProviderConfig with a fresh bearer token."""
104-
token = self.credential.get_token(COGNITIVE_SERVICES_SCOPE).token
161+
token = self.credential.get_token(SCOPE).token
105162
return ProviderConfig(
106163
type="openai",
107164
base_url=f"{self.foundry_url}/openai/v1/",
@@ -124,25 +181,41 @@ class ManagedIdentityCopilotAgent:
124181
return response.data.content if response else ""
125182
```
126183

127-
## Node.js / TypeScript example
184+
</details>
185+
186+
<details>
187+
<summary><strong>TypeScript</strong></summary>
188+
189+
### Prerequisites
190+
191+
Install the required packages:
192+
193+
```bash
194+
npm install @github/copilot-sdk @azure/identity
195+
```
196+
197+
### Basic usage
128198

129199
<!-- docs-validate: skip -->
200+
130201
```typescript
131202
import { DefaultAzureCredential } from "@azure/identity";
132203
import { CopilotClient } from "@github/copilot-sdk";
133204

134-
const credential = new DefaultAzureCredential();
205+
const credential = new DefaultAzureCredential({
206+
requiredEnvVars: ["AZURE_TOKEN_CREDENTIALS"],
207+
});
135208
const tokenResponse = await credential.getToken(
136-
"https://cognitiveservices.azure.com/.default"
209+
"https://ai.azure.com/.default"
137210
);
138211

139212
const client = new CopilotClient();
140213

141214
const session = await client.createSession({
142-
model: "gpt-4.1",
215+
model: "gpt-5.5",
143216
provider: {
144217
type: "openai",
145-
baseUrl: `${process.env.AZURE_AI_FOUNDRY_RESOURCE_URL}/openai/v1/`,
218+
baseUrl: `${process.env.FOUNDRY_RESOURCE_URL}/openai/v1/`,
146219
bearerToken: tokenResponse.token,
147220
wireApi: "responses",
148221
},
@@ -154,43 +227,14 @@ console.log(response?.data.content);
154227
await client.stop();
155228
```
156229

157-
## .NET example
158-
159-
<!-- docs-validate: skip -->
160-
```csharp
161-
using Azure.Identity;
162-
using GitHub.Copilot;
163-
164-
var credential = new DefaultAzureCredential();
165-
var token = await credential.GetTokenAsync(
166-
new Azure.Core.TokenRequestContext(
167-
new[] { "https://cognitiveservices.azure.com/.default" }));
168-
169-
await using var client = new CopilotClient();
170-
var foundryUrl = Environment.GetEnvironmentVariable("AZURE_AI_FOUNDRY_RESOURCE_URL");
171-
172-
await using var session = await client.CreateSessionAsync(new SessionConfig
173-
{
174-
Model = "gpt-4.1",
175-
Provider = new ProviderConfig
176-
{
177-
Type = "openai",
178-
BaseUrl = $"{foundryUrl!.TrimEnd('/')}/openai/v1/",
179-
BearerToken = token.Token,
180-
WireApi = "responses",
181-
},
182-
});
183-
184-
var response = await session.SendAndWaitAsync(
185-
new MessageOptions { Prompt = "Hello from Managed Identity!" });
186-
Console.WriteLine(response?.Data.Content);
187-
```
230+
</details>
188231

189232
## Environment configuration
190233

191234
| Variable | Description | Example |
192235
|----------|-------------|---------|
193-
| `AZURE_AI_FOUNDRY_RESOURCE_URL` | Your Azure AI Foundry resource URL | `https://myresource.openai.azure.com` |
236+
| `AZURE_TOKEN_CREDENTIALS` | When running in **Azure**, set it to `ManagedIdentityCredential`. When running **locally**, set it to either `dev` or a developer tool credential name, such as `AzureCliCredential`. | |
237+
| `FOUNDRY_RESOURCE_URL` | Your Microsoft Foundry resource URL | `https://<my-resource>.openai.azure.com` |
194238

195239
No API key environment variable is needed—authentication is handled by `DefaultAzureCredential`, which automatically supports:
196240

@@ -199,14 +243,18 @@ No API key environment variable is needed—authentication is handled by `Defaul
199243
* **Environment variables** (`AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET`): for service principals
200244
* **Workload Identity**: for Kubernetes
201245

202-
See the [DefaultAzureCredential documentation](https://learn.microsoft.com/python/api/azure-identity/azure.identity.defaultazurecredential) for the full credential chain.
246+
See the `DefaultAzureCredential` documentation for the full credential chain:
247+
248+
* [.NET](https://aka.ms/azsdk/net/identity/credential-chains#defaultazurecredential-overview)
249+
* [Python](https://aka.ms/azsdk/python/identity/credential-chains#defaultazurecredential-overview)
250+
* [TypeScript](https://aka.ms/azsdk/js/identity/credential-chains#defaultazurecredential-overview)
203251

204252
## When to use this pattern
205253

206254
| Scenario | Recommendation |
207255
|----------|----------------|
208256
| Azure-hosted app with Managed Identity | ✅ Use this pattern |
209-
| App with existing Azure AD service principal | ✅ Use this pattern |
257+
| App with existing Microsoft Entra service principal | ✅ Use this pattern |
210258
| Local development with `az login` | ✅ Use this pattern |
211259
| Non-Azure environment with static API key | Use [standard BYOK](../auth/byok.md) |
212260
| GitHub Copilot subscription available | Use [GitHub OAuth](./github-oauth.md) |

0 commit comments

Comments
 (0)