Liking cljdoc? Tell your friends :D

BYOK (Bring Your Own Key)

BYOK allows you to use the Copilot SDK with your own API keys from model providers, bypassing GitHub Copilot authentication. This is useful for enterprise deployments, custom model hosting, or when you want direct billing with your model provider.

Supported Providers

ProviderType ValueNotes
OpenAI"openai"OpenAI API and OpenAI-compatible endpoints
Azure OpenAI / Azure AI Foundry"azure"Azure-hosted models
Anthropic"anthropic"Claude models
Ollama"openai"Local models via OpenAI-compatible API
Other OpenAI-compatible"openai"vLLM, LiteLLM, etc.

Quick Start: Azure AI Foundry

Azure AI Foundry (formerly Azure OpenAI) is a common BYOK deployment target for enterprises. Here's a complete example:

Python
import asyncio
import os
from copilot import CopilotClient

FOUNDRY_MODEL_URL = "https://your-resource.openai.azure.com/openai/v1/"
# Set FOUNDRY_API_KEY environment variable

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session({
        "model": "gpt-5.2-codex",  # Your deployment name
        "provider": {
            "type": "openai",
            "base_url": FOUNDRY_MODEL_URL,
            "wire_api": "responses",  # Use "completions" for older models
            "api_key": os.environ["FOUNDRY_API_KEY"],
        },
    })

    done = asyncio.Event()

    def on_event(event):
        if event.type.value == "assistant.message":
            print(event.data.content)
        elif event.type.value == "session.idle":
            done.set()

    session.on(on_event)
    await session.send({"prompt": "What is 2+2?"})
    await done.wait()

    await session.destroy()
    await client.stop()

asyncio.run(main())
Node.js / TypeScript
import { CopilotClient } from "copilot-sdk-supercharged";

const FOUNDRY_MODEL_URL = "https://your-resource.openai.azure.com/openai/v1/";

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-5.2-codex",  // Your deployment name
    provider: {
        type: "openai",
        baseUrl: FOUNDRY_MODEL_URL,
        wireApi: "responses",  // Use "completions" for older models
        apiKey: process.env.FOUNDRY_API_KEY,
    },
});

session.on("assistant.message", (event) => {
    console.log(event.data.content);
});

await session.sendAndWait({ prompt: "What is 2+2?" });
await client.stop();
Go
package main

import (
    "context"
    "fmt"
    "os"
    copilot "github.com/jeremiahjordanisaacson/copilot-sdk-supercharged/go"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)
    if err := client.Start(ctx); err != nil {
        panic(err)
    }
    defer client.Stop()

    session, err := client.CreateSession(ctx, &copilot.SessionConfig{
        Model: "gpt-5.2-codex",  // Your deployment name
        Provider: &copilot.ProviderConfig{
            Type:    "openai",
            BaseURL: "https://your-resource.openai.azure.com/openai/v1/",
            WireApi: "responses",  // Use "completions" for older models
            APIKey:  os.Getenv("FOUNDRY_API_KEY"),
        },
    })
    if err != nil {
        panic(err)
    }

    response, err := session.SendAndWait(ctx, copilot.MessageOptions{
        Prompt: "What is 2+2?",
    })
    if err != nil {
        panic(err)
    }

    fmt.Println(*response.Data.Content)
}
.NET
using GitHub.Copilot.SDK;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-5.2-codex",  // Your deployment name
    Provider = new ProviderConfig
    {
        Type = "openai",
        BaseUrl = "https://your-resource.openai.azure.com/openai/v1/",
        WireApi = "responses",  // Use "completions" for older models
        ApiKey = Environment.GetEnvironmentVariable("FOUNDRY_API_KEY"),
    },
});

var response = await session.SendAndWaitAsync(new MessageOptions
{
    Prompt = "What is 2+2?",
});
Console.WriteLine(response?.Data.Content);

Provider Configuration Reference

ProviderConfig Fields

FieldTypeDescription
type"openai" | "azure" | "anthropic"Provider type (default: "openai")
baseUrl / base_urlstringRequired. API endpoint URL
apiKey / api_keystringAPI key (optional for local providers like Ollama)
bearerToken / bearer_tokenstringBearer token auth (takes precedence over apiKey)
wireApi / wire_api"completions" | "responses"API format (default: "completions")
azure.apiVersion / azure.api_versionstringAzure API version (default: "2024-10-21")

Wire API Format

The wireApi setting determines which OpenAI API format to use:

  • "completions" (default) - Chat Completions API (/chat/completions). Use for most models.
  • "responses" - Responses API. Use for GPT-5 series models that support the newer responses format.

Type-Specific Notes

OpenAI (type: "openai")

  • Works with OpenAI API and any OpenAI-compatible endpoint
  • baseUrl should include the full path (e.g., https://api.openai.com/v1)

Azure (type: "azure")

  • Use for native Azure OpenAI endpoints
  • baseUrl should be just the host (e.g., https://my-resource.openai.azure.com)
  • Do NOT include /openai/v1 in the URL—the SDK handles path construction

Anthropic (type: "anthropic")

  • For direct Anthropic API access
  • Uses Claude-specific API format

Example Configurations

OpenAI Direct

provider: {
    type: "openai",
    baseUrl: "https://api.openai.com/v1",
    apiKey: process.env.OPENAI_API_KEY,
}

Azure OpenAI (Native Azure Endpoint)

Use type: "azure" for endpoints at *.openai.azure.com:

provider: {
    type: "azure",
    baseUrl: "https://my-resource.openai.azure.com",  // Just the host
    apiKey: process.env.AZURE_OPENAI_KEY,
    azure: {
        apiVersion: "2024-10-21",
    },
}

Azure AI Foundry (OpenAI-Compatible Endpoint)

For Azure AI Foundry deployments with /openai/v1/ endpoints, use type: "openai":

provider: {
    type: "openai",
    baseUrl: "https://your-resource.openai.azure.com/openai/v1/",
    apiKey: process.env.FOUNDRY_API_KEY,
    wireApi: "responses",  // For GPT-5 series models
}

Ollama (Local)

provider: {
    type: "openai",
    baseUrl: "http://localhost:11434/v1",
    // No apiKey needed for local Ollama
}

Anthropic

provider: {
    type: "anthropic",
    baseUrl: "https://api.anthropic.com",
    apiKey: process.env.ANTHROPIC_API_KEY,
}

Bearer Token Authentication

Some providers require bearer token authentication instead of API keys:

provider: {
    type: "openai",
    baseUrl: "https://my-custom-endpoint.example.com/v1",
    bearerToken: process.env.MY_BEARER_TOKEN,  // Sets Authorization header
}

Note: The bearerToken option accepts a static token string only. The SDK does not refresh this token automatically. If your token expires, requests will fail and you'll need to create a new session with a fresh token.

Limitations

When using BYOK, be aware of these limitations:

Identity Limitations

BYOK authentication uses static credentials only. The following identity providers are NOT supported:

  • Microsoft Entra ID (Azure AD) - No support for Entra managed identities or service principals
  • Third-party identity providers - No OIDC, SAML, or other federated identity
  • Managed identities - Azure Managed Identity is not supported

You must use an API key or static bearer token that you manage yourself.

Why not Entra ID? While Entra ID does issue bearer tokens, these tokens are short-lived (typically 1 hour) and require automatic refresh via the Azure Identity SDK. The bearerToken option only accepts a static string—there is no callback mechanism for the SDK to request fresh tokens. For long-running workloads requiring Entra authentication, you would need to implement your own token refresh logic and create new sessions with updated tokens.

Feature Limitations

Some Copilot features may behave differently with BYOK:

  • Model availability - Only models supported by your provider are available
  • Rate limiting - Subject to your provider's rate limits, not Copilot's
  • Usage tracking - Usage is tracked by your provider, not GitHub Copilot
  • Premium requests - Do not count against Copilot premium request quotas

Provider-Specific Limitations

ProviderLimitations
Azure AI FoundryNo Entra ID auth; must use API keys
OllamaNo API key; local only; model support varies
OpenAISubject to OpenAI rate limits and quotas

Troubleshooting

"Model not specified" Error

When using BYOK, the model parameter is required:

// ❌ Error: Model required with custom provider
const session = await client.createSession({
    provider: { type: "openai", baseUrl: "..." },
});

// ✅ Correct: Model specified
const session = await client.createSession({
    model: "gpt-4",  // Required!
    provider: { type: "openai", baseUrl: "..." },
});

Azure Endpoint Type Confusion

For Azure OpenAI endpoints (*.openai.azure.com), use the correct type:

// ❌ Wrong: Using "openai" type with native Azure endpoint
provider: {
    type: "openai",  // This won't work correctly
    baseUrl: "https://my-resource.openai.azure.com",
}

// ✅ Correct: Using "azure" type
provider: {
    type: "azure",
    baseUrl: "https://my-resource.openai.azure.com",
}

However, if your Azure AI Foundry deployment provides an OpenAI-compatible endpoint path (e.g., /openai/v1/), use type: "openai":

// ✅ Correct: OpenAI-compatible Azure AI Foundry endpoint
provider: {
    type: "openai",
    baseUrl: "https://your-resource.openai.azure.com/openai/v1/",
}

Connection Refused (Ollama)

Ensure Ollama is running and accessible:

# Check Ollama is running
curl http://localhost:11434/v1/models

# Start Ollama if not running
ollama serve

Authentication Failed

  1. Verify your API key is correct and not expired
  2. Check the baseUrl matches your provider's expected format
  3. For bearer tokens, ensure the full token is provided (not just a prefix)

Next Steps

Can you improve this documentation? These fine people already did:
Patrick Nikoletich & Jeremiah Isaacson
Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close