⚠️ 警告:此库可能违反 GitHub Copilot 的服务条款。使用此库在未获得适当授权的情况下访问 GitHub Copilot 可能导致账号被暂停或终止。本项目仅供教育和研究目的使用。使用风险自负,请确保在使用此库之前获得适当的授权。
OAuth2 设备流认证的 TypeScript 实现,支持 GitHub Copilot 和 Hyper 服务集成。
- ✅ 设备流认证:实现 OAuth2 设备授权流程
- ✅ Token 生命周期管理:自动过期检测和刷新
- ✅ 多服务支持:GitHub Copilot 和 Hyper 服务适配器
- ✅ 磁盘缓存:从官方 GitHub Copilot 客户端缓存读取 Token
- ✅ 类型安全:完整的 TypeScript 类型定义
- ✅ 错误处理:全面的错误处理和重试机制
- ✅ 异步支持:现代 async/await 编程支持
npm installnpm run buildimport { copilot, Token } from "oauth-deviceflow";
async function authenticate() {
// 尝试从磁盘缓存读取 token
const githubToken = copilot.refreshTokenFromDisk();
let token: Token;
if (githubToken) {
token = await copilot.refreshToken(githubToken);
} else {
// 启动设备流
const deviceCode = await copilot.requestDeviceCode();
console.log(`访问: ${deviceCode.verificationUri}`);
console.log(`输入代码: ${deviceCode.userCode}`);
// 轮询获取 token
token = await copilot.pollForToken(deviceCode);
}
console.log(`访问令牌: ${token.accessToken}`);
}
authenticate().catch(console.error);import { hyper, Token } from "oauth-deviceflow";
async function authenticate() {
// 启动设备授权
const auth = await hyper.initiateDeviceAuth();
console.log(`访问: ${auth.verificationUrl}`);
console.log(`输入代码: ${auth.userCode}`);
// 轮询获取刷新令牌
const refreshToken = await hyper.pollForToken(auth.deviceCode, auth.expiresIn);
// 交换访问令牌
let token = await hyper.exchangeToken(refreshToken);
// 检查 token 是否过期
if (token.isExpired()) {
token = await hyper.exchangeToken(refreshToken);
}
console.log(`访问令牌: ${token.accessToken}`);
}
authenticate().catch(console.error);src/
├── index.ts # 包入口点
├── token.ts # Token 数据结构和生命周期管理
├── copilot/ # GitHub Copilot 集成
│ ├── index.ts
│ ├── oauth.ts # 设备流实现
│ ├── disk.ts # 磁盘缓存读取
│ ├── client.ts # 带拦截器的 HTTP 客户端
│ ├── http.ts # HTTP 请求头
│ └── urls.ts # URL 常量
└── hyper/ # Hyper 服务集成
├── index.ts
└── device.ts # 设备流实现
import { Token } from "oauth-deviceflow";
// 创建 token
const token = new Token(
"access_token_here",
"refresh_token_here",
3600,
0
);
// 设置过期时间戳
token.setExpiresAt();
// 检查是否过期(带有 10% 的缓冲)
if (token.isExpired()) {
// 刷新 token
}
// 序列化为 JSON
const data = token.toJSON();
// 从 JSON 反序列化
const token2 = Token.fromJSON(data);import { copilot } from "oauth-deviceflow";
// 请求设备码
const deviceCode = await copilot.requestDeviceCode(30000);
// 轮询获取 token(阻塞直到授权或超时)
const token = await copilot.pollForToken(deviceCode, 600000);
// 刷新 Copilot token
const newToken = await copilot.refreshToken(githubToken);
// 从磁盘缓存读取
const githubToken = copilot.refreshTokenFromDisk();
// 创建带有 X-Initiator 请求头注入的 HTTP 客户端
const client = copilot.createClient(false, true);import { hyper } from "oauth-deviceflow";
// 发起设备授权
const auth = await hyper.initiateDeviceAuth(30000);
// 轮询获取刷新令牌
const refreshToken = await hyper.pollForToken(auth.deviceCode, auth.expiresIn);
// 交换访问令牌
const token = await hyper.exchangeToken(refreshToken, 30000);
// 内省令牌 (RFC 7662)
const info = await hyper.introspectToken(token.accessToken);
if (info.active) {
console.log(`用户 ID: ${info.sub}`);
}import { copilot } from "oauth-deviceflow";
try {
const token = await copilot.pollForToken(deviceCode);
} catch (error) {
if (error instanceof copilot.NotAvailableError) {
console.error("GitHub Copilot 对此账户不可用");
} else if (error.message === "Authorization timed out") {
console.error("授权超时");
} else {
console.error("网络错误:", error);
}
}- Node.js 16+
- TypeScript 5.3+
- axios >= 1.6.0
- 姓名:Shibo Li
- 邮箱:shadow.li981@gmail.com
本项目受以下项目启发并参考:
MIT License