Skip to content

OAuth Library - Design Document

English | 中文

⚠️ WARNING: This library may violate GitHub Copilot's Terms of Service. Using this library to access GitHub Copilot without proper authorization may result in account suspension or termination. This project is for educational and research purposes only. Use at your own risk and ensure you have appropriate authorization before using this library.

1. Project Overview

This is a multi-language OAuth authentication library specifically designed to provide Device Flow authentication for GitHub Copilot and Hyper services. The project implements the standard OAuth2.0 Device Authorization Grant (RFC 8628) and provides specialized integration modules for two different services.

Supported Languages: - Go - Original implementation, located in go/ directory - Python - Located in python/ directory
- TypeScript - Located in ts/ directory

1.1 Core Values

  • Unified Token Management: Provides unified token data structure and lifecycle management
  • Multi-Service Support: Supports both GitHub Copilot and Hyper authentication scenarios
  • Automatic Refresh: Built-in token expiration detection and automatic refresh logic
  • Device Flow Authentication: Enables user authorization without a browser (suitable for CLI tools)
  • Multi-Language Support: Complete implementations in Go, Python, and TypeScript

1.2 Project Structure

oauth/
├── docs/
│   ├── design_EN.md       # English design document
│   └── design_CN.md       # Chinese design document
├── go/                     # Go implementation
│   ├── go.mod
│   ├── README_EN.md
│   ├── README_CN.md
│   ├── token.go
│   ├── copilot/
│   │   ├── oauth.go       # Device flow
│   │   ├── client.go      # Custom HTTP client
│   │   ├── disk.go        # Disk cache
│   │   ├── http.go        # HTTP headers
│   │   └── urls.go        # URL constants
│   └── hyper/
│       └── device.go      # Hyper device flow
├── python/                 # Python implementation
│   ├── setup.py
│   ├── requirements.txt
│   ├── README_EN.md
│   ├── README_CN.md
│   └── oauth/
│       ├── token.py
│       ├── copilot/
│       └── hyper/
└── ts/                     # TypeScript implementation
    ├── package.json
    ├── tsconfig.json
    ├── README_EN.md
    ├── README_CN.md
    └── src/
        ├── token.ts
        ├── copilot/
        └── hyper/

2. Architecture Design

2.1 Layered Architecture

┌──────────────────────────────────────────┐
│      Application Layer (CLI/Service)     │
├──────────────────────────────────────────┤
│   copilot/        │      hyper/          │  ← Service Adapter Layer
├───────────────────┼──────────────────────┤
│          Token Management (Core)         │  ← Core Layer
├──────────────────────────────────────────┤
│      HTTP Client / Transport Layer       │
└──────────────────────────────────────────┘

2.2 Module Design

Core Module (Token Management) - Language-agnostic token data structure - Lifecycle management (creation, expiration check, refresh) - Serialization/deserialization support

Service Adapter Layer - copilot/: GitHub Copilot-specific implementation - hyper/: Hyper service-specific implementation

Transport Layer - Standard HTTP client with timeout - Custom interceptors (e.g., X-Initiator header injection) - Response size limiting (1MB max)

3. Core Design Principles

3.1 Token Abstraction

Design Philosophy: Separate token management from service-specific logic to enable reusability across different OAuth providers.

Key Features: 1. Dual Time Representation - expires_in: Relative time in seconds (for API responses) - expires_at: Absolute Unix timestamp (for expiration checks) - Automatic conversion between the two

  1. Smart Expiration Detection
  2. 10% buffer before actual expiration
  3. Prevents using tokens near their expiration time
  4. Provides time for token refresh

  5. Serialization Support

  6. Go: JSON tags for encoding/json
  7. Python: to_dict() and from_dict() methods
  8. TypeScript: toJSON() and fromJSON() methods

3.2 GitHub Copilot Integration

Three-Stage Authentication Flow:

1. Device Code Request
   GitHub returns device_code and user_code
2. User Authorization
   User visits GitHub and enters user_code
3. Token Polling
   App polls GitHub for access token
4. Copilot Token Exchange
   Exchange GitHub token for Copilot token

Key Design Decisions:

  1. Disk Cache Reading
  2. Reads tokens from official GitHub Copilot client cache
  3. Platform-specific paths:
    • Windows: %LOCALAPPDATA%/github-copilot/apps.json
    • macOS/Linux: ~/.config/github-copilot/apps.json
  4. Graceful fallback if cache unavailable

  5. X-Initiator Header Injection

  6. Custom HTTP client/adapter that inspects request body
  7. Sets X-Initiator: user for user-initiated requests
  8. Sets X-Initiator: agent for agent/assistant messages
  9. Uses regex pattern matching to detect assistant messages

  10. Error Handling

  11. Specific error for "Copilot not available" (HTTP 403)
  12. Retry logic for authorization_pending
  13. Backoff for slow_down errors (increments interval by 5s)

3.3 Hyper Service Integration

Device Flow with Callbacks:

1. Initiate Device Auth
   Hyper returns device_code, user_code, verification_url
2. User Authorization
   User visits verification_url and enters user_code
3. Token Polling
   Poll until authorization complete
4. Success Callback (optional)
   Trigger callback with user ID
5. Token Exchange
   Exchange refresh token for access token

Key Features:

  1. Environment Configuration
  2. Base URL configurable via HYPER_BASE_URL environment variable
  3. Default: https://api.hyper.example.com

  4. Token Introspection

  5. Implements RFC 7662 (OAuth 2.0 Token Introspection)
  6. Validates token status and retrieves metadata
  7. Returns user ID, organization ID, expiration time

  8. Success Callbacks

  9. Optional callback function/lambda on successful authentication
  10. Receives user ID as parameter
  11. Useful for analytics and logging

3.4 Security Measures

All implementations include:

  1. Request Timeouts
  2. 30-second timeout for all HTTP requests
  3. Prevents hanging connections

  4. Response Size Limits

  5. Maximum 1MB response body
  6. Prevents memory exhaustion attacks
  7. Implemented using streaming readers

  8. Token Refresh Strategy

  9. Tokens refreshed at 90% of their lifetime
  10. 10% buffer prevents edge-case failures
  11. Automatic refresh on isExpired() check

  12. Error Handling

  13. Specific exception types for different error scenarios
  14. Proper HTTP status code handling
  15. Graceful degradation when optional features unavailable

4. Implementation Differences

4.1 Go Implementation

Characteristics: - Uses standard library net/http - Context-based cancellation and timeouts - Interface-based design for extensibility - No external dependencies for core functionality

Code Style:

// Context throughout
func RequestDeviceCode(ctx context.Context) (*DeviceCode, error)

// Explicit error handling
if err != nil {
    return nil, fmt.Errorf("request failed: %w", err)
}

// Defer for cleanup
defer resp.Body.Close()

4.2 Python Implementation

Characteristics: - Uses requests library for HTTP - Dataclasses for structured data - Type hints for better IDE support - Pythonic error handling

Code Style:

# Dataclasses
@dataclass
class Token:
    access_token: str
    refresh_token: str

# Type hints
def request_device_code(timeout: int = 30) -> DeviceCode:

# Context managers
with requests.Session() as session:
    response = session.post(url)

4.3 TypeScript Implementation

Characteristics: - Uses axios for HTTP requests - Full TypeScript type safety - Async/await for all I/O operations - ES6+ features (classes, arrow functions)

Code Style:

// Class-based
class Token {
  constructor(
    public accessToken: string,
    public refreshToken: string,
    public expiresIn: number,
    public expiresAt: number
  ) {}
}

// Async/await
async function requestDeviceCode(timeout: number = 30000): Promise<DeviceCode>

// Promise-based
return axios.post(url, data).then(response => response.data)

5. Testing Considerations

5.1 Unit Testing

Token Management: - Test expiration calculation - Test 10% buffer logic - Test serialization/deserialization

HTTP Mocking: - Mock device code requests - Mock token polling responses - Test retry and backoff logic

5.2 Integration Testing

End-to-End Flows: - Complete device flow authentication - Token refresh scenarios - Error handling paths

Environment Testing: - Test disk cache reading on different platforms - Test environment variable configuration - Test timeout and size limit enforcement

6. Future Enhancements

6.1 Potential Features

  1. Token Storage
  2. Secure token storage (keychain/keyring integration)
  3. Encrypted cache files
  4. Memory-only mode for sensitive environments

  5. Additional OAuth Providers

  6. Generic OAuth2 device flow client
  7. Support for other services using device flow

  8. Improved Observability

  9. Structured logging
  10. Metrics/telemetry hooks
  11. Debug mode with request/response logging

  12. Rate Limiting

  13. Client-side rate limiting
  14. Respect Retry-After headers
  15. Exponential backoff improvements

6.2 Performance Optimizations

  1. Connection Pooling
  2. Reuse HTTP connections
  3. Connection keep-alive

  4. Caching

  5. Cache device codes
  6. Cache user codes for retry scenarios

7. Best Practices for Users

7.1 Error Handling

Always handle specific errors:

try:
    token = poll_for_token(device_code)
except NotAvailableError:
    print("GitHub Copilot not available for this account")
except TimeoutError:
    print("Authentication timed out")
except Exception as e:
    print(f"Unexpected error: {e}")

7.2 Token Management

Check expiration before use:

if (token.isExpired()) {
  token = await refreshToken(token.refreshToken);
}
// Use token
await makeAuthenticatedRequest(token.accessToken);

7.3 Configuration

Use environment variables for configuration:

export HYPER_BASE_URL=https://api.hyper.example.com

Author

  • Name: Shibo Li
  • Email: shadow.li981@gmail.com

References

This project is inspired by and references: - charmbracelet/crush - RFC 8628 - OAuth 2.0 Device Authorization Grant - RFC 7662 - OAuth 2.0 Token Introspection

License

MIT License