# How Headroom Handles GitHub Copilot CLI Subscription Authentication

> Discover how Headroom authenticates GitHub Copilot subscription mode by finding OAuth tokens, exchanging them for API tokens, and injecting them into Copilot requests.

- Repository: [Tejas Chopra/headroom](https://github.com/chopratejas/headroom)
- Tags: how-to-guide
- Published: 2026-06-08

---

**Headroom authenticates the GitHub Copilot subscription flow by discovering a reusable GitHub OAuth token, optionally exchanging it for a short-lived Copilot API token, and then injecting that token into every request that targets the Copilot endpoint.**

The `chopratejas/headroom` project implements a robust authentication pipeline for GitHub Copilot CLI subscription mode through its core authentication module. This system prioritizes token security by validating credentials against GitHub's Copilot user-info endpoint before allowing API access.

## Token Discovery and OAuth Resolution

Headroom implements a cascading token discovery system in [`headroom/copilot_auth.py`](https://github.com/chopratejas/headroom/blob/main/headroom/copilot_auth.py) that examines multiple credential sources in priority order.

### Environment Variable Shortcuts

The authentication process begins with `resolve_client_bearer_token`, which checks for explicitly configured API tokens first. The function scans for `GITHUB_COPILOT_API_TOKEN` followed by generic GitHub token variables including `GH_TOKEN` and `GITHUB_TOKEN`.

If a direct API token is not found in the environment, Headroom falls back to an OAuth-style discovery mechanism through `iter_oauth_token_candidates`. This function searches:

- Environment variables (`GITHUB_COPILOT_GITHUB_TOKEN`, `GITHUB_COPILOT_TOKEN`)
- Platform-specific credential stores (Windows Credential Manager, macOS Keychain, Linux Secret Service)
- Copilot credential files located at `~/.config/github-copilot/*.json`
- GitHub CLI authentication via `gh auth token`

The discovery logic prioritizes the safest token locations first, ensuring that system keychains are preferred over plaintext files when available.

### Subscription-Specific Validation

Once candidate tokens are identified, `resolve_subscription_bearer_token` validates each credential against the Copilot user-info endpoint (`/copilot_internal/user`). This verification step ensures that only tokens with active Copilot subscriptions are accepted. The first token that receives a successful response from the GitHub API becomes the **subscription bearer token** used for subsequent requests.

## Optional Token Exchange Mechanism

Headroom supports an advanced token exchange workflow governed by the `GITHUB_COPILOT_USE_TOKEN_EXCHANGE` environment variable. When this flag is set to a truthy value, the system calls `_should_exchange_oauth_token` to trigger the exchange process.

The `CopilotTokenProvider._exchange_token_sync` method makes a `GET` request to `https://api.github.com/copilot_internal/v2/token`, exchanging the long-lived OAuth token for a short-lived Copilot API token. This exchange returns an explicit API endpoint, the temporary token, and expiry information that the provider uses for automatic rotation.

## Request Header Injection

All outbound HTTP requests pass through `apply_copilot_api_auth` before reaching the Copilot API. This function performs three critical operations:

1. Checks `is_copilot_api_url` to confirm the request targets `api.githubcopilot.com`
2. Retrieves a fresh token from the shared `CopilotTokenProvider` via `get_api_token`
3. Replaces any existing `Authorization` header with `Bearer <token>`

This interception ensures that every proxied request carries valid authentication credentials without requiring manual header management from the user.

## End-to-End Authentication Flow

When a user executes the subscription mode wrapper:

```bash
headroom wrap copilot --subscription -- --model gpt-4o

```

The system instantiates a local proxy that manages authentication automatically. On the first request to the Copilot API, `apply_copilot_api_auth` triggers the resolution pipeline. An OAuth token is discovered and validated, optionally exchanged for a short-lived token, and cached in `CopilotTokenProvider._cached` for the lifetime of the proxy process (defaulting to one hour). Subsequent requests reuse the cached token until expiration, at which point the provider automatically fetches fresh credentials.

## Practical Implementation Examples

### Obtaining the Subscription Token in Python

```python
from headroom import copilot_auth

# Resolve the token that the Copilot subscription API will accept

subscription_token = copilot_auth.resolve_subscription_bearer_token()
print("Subscription token:", subscription_token)

```

This calls the same discovery and validation logic that the CLI wrapper uses internally.

### Using the Token Provider Directly

```python
import asyncio
from headroom.copilot_auth import get_copilot_token_provider

async def fetch_token():
    provider = get_copilot_token_provider()
    token = await provider.get_api_token()
    print("API token:", token.token)
    print("Expires at:", token.expires_at)

asyncio.run(fetch_token())

```

The provider automatically handles OAuth token exchange based on the `GITHUB_COPILOT_USE_TOKEN_EXCHANGE` environment variable.

### Configuring the Environment

```bash

# Export a generic GitHub token as fallback

export GH_TOKEN=ghp_XXXXXXXXXXXXXXXXXXXX

# Enable token exchange for short-lived tokens (optional)

export GITHUB_COPILOT_USE_TOKEN_EXCHANGE=true

# Run the proxy with automatic authentication injection

headroom wrap copilot --subscription -- --model gpt-4o

```

## Summary

- **Multi-source token discovery** in [`headroom/copilot_auth.py`](https://github.com/chopratejas/headroom/blob/main/headroom/copilot_auth.py) checks environment variables, system keychains, and credential files to locate valid OAuth tokens.
- **Subscription validation** occurs against the `/copilot_internal/user` endpoint to ensure tokens have active Copilot access before use.
- **Optional token exchange** converts long-lived OAuth tokens into short-lived API tokens when `GITHUB_COPILOT_USE_TOKEN_EXCHANGE` is enabled.
- **Automatic header injection** via `apply_copilot_api_auth` ensures all proxied requests to `api.githubcopilot.com` include valid `Bearer` tokens.
- **In-memory caching** in `CopilotTokenProvider._cached` minimizes authentication overhead while respecting token expiration times.

## Frequently Asked Questions

### What environment variables does Headroom check for GitHub Copilot authentication?

Headroom checks `GITHUB_COPILOT_API_TOKEN` first, then falls back to generic GitHub tokens (`GH_TOKEN`, `GITHUB_TOKEN`). For OAuth-style discovery, it examines `GITHUB_COPILOT_GITHUB_TOKEN` and `GITHUB_COPILOT_TOKEN` before querying system credential stores and the GitHub CLI.

### How does Headroom validate OAuth tokens for subscription mode?

The `resolve_subscription_bearer_token` function iterates over discovered token candidates and validates each against the GitHub Copilot user-info endpoint (`/copilot_internal/user`). Only tokens that return successful responses—indicating active Copilot subscriptions—are accepted for API requests.

### What is the purpose of the token exchange mechanism in Headroom?

When `GITHUB_COPILOT_USE_TOKEN_EXCHANGE` is set to true, Headroom exchanges long-lived OAuth tokens for short-lived Copilot API tokens via the `/copilot_internal/v2/token` endpoint. This improves security by reducing the exposure window of credentials and provides explicit expiration metadata for automatic rotation.

### How long are tokens cached when using Headroom's Copilot wrapper?

Tokens are cached in `CopilotTokenProvider._cached` for the duration of the proxy process, defaulting to one hour or until the token's expiration time—whichever comes first. The provider automatically refreshes the token when it expires or when explicitly invalidated.