The Copilot SDK's BYOK mode 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.
This guide shows how to use DefaultAzureCredential from the Azure Identity library to authenticate with Azure AI Foundry models through the Copilot SDK.
Azure AI Foundry's OpenAI-compatible endpoint accepts bearer tokens from Entra ID in place of static API keys. The pattern is:
DefaultAzureCredential to obtain a token for the https://cognitiveservices.azure.com/.default scopebearer_token in the BYOK provider configsequenceDiagram
participant App as Your Application
participant AAD as Entra ID
participant SDK as Copilot SDK
participant Foundry as Azure AI Foundry
App->>AAD: DefaultAzureCredential.get_token()
AAD-->>App: Bearer token (~1hr)
App->>SDK: create_session(provider={bearer_token: token})
SDK->>Foundry: Request with Authorization: Bearer <token>
Foundry-->>SDK: Model response
SDK-->>App: Session events
pip install github-copilot-sdk azure-identity
import asyncio
import os
from azure.identity import DefaultAzureCredential
from copilot import CopilotClient
from copilot.session import PermissionHandler, ProviderConfig
COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default"
async def main():
# Get a token using Managed Identity, Azure CLI, or other credential chain
credential = DefaultAzureCredential()
token = credential.get_token(COGNITIVE_SERVICES_SCOPE).token
foundry_url = os.environ["AZURE_AI_FOUNDRY_RESOURCE_URL"]
client = CopilotClient()
await client.start()
session = await client.create_session(
on_permission_request=PermissionHandler.approve_all,
model="gpt-4.1",
provider=ProviderConfig(
type="openai",
base_url=f"{foundry_url.rstrip('/')}/openai/v1/",
bearer_token=token, # Short-lived bearer token
wire_api="responses",
),
)
response = await session.send_and_wait("Hello from Managed Identity!")
print(response.data.content)
await client.stop()
asyncio.run(main())
Bearer tokens expire (typically after ~1 hour). For servers or long-running agents, refresh the token before creating each session:
from azure.identity import DefaultAzureCredential
from copilot import CopilotClient
from copilot.session import PermissionHandler, ProviderConfig
COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default"
class ManagedIdentityCopilotAgent:
"""Copilot agent that refreshes Entra ID tokens for Azure AI Foundry."""
def __init__(self, foundry_url: str, model: str = "gpt-4.1"):
self.foundry_url = foundry_url.rstrip("/")
self.model = model
self.credential = DefaultAzureCredential()
self.client = CopilotClient()
def _get_provider_config(self) -> ProviderConfig:
"""Build a ProviderConfig with a fresh bearer token."""
token = self.credential.get_token(COGNITIVE_SERVICES_SCOPE).token
return ProviderConfig(
type="openai",
base_url=f"{self.foundry_url}/openai/v1/",
bearer_token=token,
wire_api="responses",
)
async def chat(self, prompt: str) -> str:
"""Send a prompt and return the response text."""
# Fresh token for each session
session = await self.client.create_session(
on_permission_request=PermissionHandler.approve_all,
model=self.model,
provider=self._get_provider_config(),
)
response = await session.send_and_wait(prompt)
await session.disconnect()
return response.data.content if response else ""
import { DefaultAzureCredential } from "@azure/identity";
import { CopilotClient } from "@github/copilot-sdk";
const credential = new DefaultAzureCredential();
const tokenResponse = await credential.getToken(
"https://cognitiveservices.azure.com/.default"
);
const client = new CopilotClient();
const session = await client.createSession({
model: "gpt-4.1",
provider: {
type: "openai",
baseUrl: `${process.env.AZURE_AI_FOUNDRY_RESOURCE_URL}/openai/v1/`,
bearerToken: tokenResponse.token,
wireApi: "responses",
},
});
const response = await session.sendAndWait({ prompt: "Hello!" });
console.log(response?.data.content);
await client.stop();
using Azure.Identity;
using GitHub.Copilot;
var credential = new DefaultAzureCredential();
var token = await credential.GetTokenAsync(
new Azure.Core.TokenRequestContext(
new[] { "https://cognitiveservices.azure.com/.default" }));
await using var client = new CopilotClient();
var foundryUrl = Environment.GetEnvironmentVariable("AZURE_AI_FOUNDRY_RESOURCE_URL");
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
Provider = new ProviderConfig
{
Type = "openai",
BaseUrl = $"{foundryUrl!.TrimEnd('/')}/openai/v1/",
BearerToken = token.Token,
WireApi = "responses",
},
});
var response = await session.SendAndWaitAsync(
new MessageOptions { Prompt = "Hello from Managed Identity!" });
Console.WriteLine(response?.Data.Content);
| Variable | Description | Example |
|---|---|---|
AZURE_AI_FOUNDRY_RESOURCE_URL | Your Azure AI Foundry resource URL | https://myresource.openai.azure.com |
No API key environment variable is needed — authentication is handled by DefaultAzureCredential, which automatically supports:
az login) — for local developmentAZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET) — for service principalsSee the DefaultAzureCredential documentation for the full credential chain.
| Scenario | Recommendation |
|---|---|
| Azure-hosted app with Managed Identity | ✅ Use this pattern |
| App with existing Azure AD service principal | ✅ Use this pattern |
Local development with az login | ✅ Use this pattern |
| Non-Azure environment with static API key | Use standard BYOK |
| GitHub Copilot subscription available | Use GitHub OAuth |
Can you improve this documentation? These fine people already did:
Brett Cannon & Patrick NikoletichEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |