GitHub OAuth设备代码流程 | AI生成和翻译

Home 2025.05

概述

这段 JavaScript 代码实现了 OAuth 2.0 设备授权认证流程(又称设备码授权),用于通过 GitHub 认证并获取访问令牌。该流程通常用于无界面应用程序(如 CLI 工具或嵌入式系统),用户无法直接通过网页浏览器进行认证授权。

在此特定场景中,代码模拟 GitHub Copilot 插件(如 Neovim 或 Vim 版本)的请求,通过伪装 Copilot 客户端的请求头来接入 GitHub 认证系统。其目标是生成可用于 GitHub API 调用的访问令牌(如通过 scope: "read:user" 读取用户信息)。

该代码作为 Node.js 脚本运行,使用 fetch 发起 HTTP 请求,通过 process 读取环境变量。运行需确保 Node.js 支持 fetch(新版本或通过 polyfill 实现)。若认证成功,代码将持续轮询 GitHub 服务器直至用户完成授权或超时。

重要提示:

逐步解析

1. 环境检查

const clientId = process.env.MY_COPILOT_CLIENT_ID;

if (!clientId) {
  console.error("MY_COPILOT_CLIENT_ID 未设置");
  process.exit(1);
}

2. 通用请求头设置

const commonHeaders = new Headers();
commonHeaders.append("accept", "application/json");
commonHeaders.append("editor-version", "Neovim/0.6.1");
commonHeaders.append("editor-plugin-version", "copilot.vim/1.16.0");
commonHeaders.append("content-type", "application/json");
commonHeaders.append("user-agent", "GithubCopilot/1.155.0");
commonHeaders.append("accept-encoding", "gzip,deflate,b");

3. getDeviceCode() 函数

async function getDeviceCode() {
  const raw = JSON.stringify({
    "client_id": clientId,
    "scope": "read:user",
  });

  const requestOptions = {
    method: "POST",
    headers: commonHeaders,
    body: raw,
  };

  const data = await fetch(
    "https://github.com/login/device/code",
    requestOptions,
  )
    .then((response) => response.json())
    .catch((error) => console.error(error));
  return data;
}

4. getAccessToken(deviceCode: string) 函数

async function getAccessToken(deviceCode: string) {
  const raw = JSON.stringify({
    "client_id": clientId,
    "device_code": deviceCode,
    "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
  });

  const requestOptions = {
    method: "POST",
    headers: commonHeaders,
    body: raw,
  };

  return await fetch(
    "https://github.com/login/oauth/access_token",
    requestOptions,
  )
    .then((response) => response.json())
    .catch((error) => console.error(error));
}

5. 主执行逻辑(立即调用异步函数)

(async function () {
  const { device_code, user_code, verification_uri, expires_in } =
    await getDeviceCode();
  console.info(`请输入用户代码:\n${user_code}\n${verification_uri}`);
  console.info(`有效期:${expires_in} 秒`);
  while (true) {
    await new Promise((resolve) => setTimeout(resolve, 5000));
    const accessToken = await getAccessToken(device_code);
    if (accessToken.error) {
      console.info(`${accessToken.error}: ${accessToken.error_description}`);
    }
    if (accessToken.access_token) {
      console.info(`访问令牌:\n${JSON.stringify(accessToken, null, 1)}`);
      break;
    }
  }
})();

端到端运行原理

  1. 步骤 1:请求设备码 → 脚本从 GitHub 获取临时代码
  2. 步骤 2:用户授权 → 用户访问 GitHub 并输入代码授予权限
  3. 步骤 3:轮询令牌 → 脚本持续向 GitHub 查询直至获得令牌
  4. 结果:获取指定作用域的访问令牌(如通过 GitHub API 读取用户数据)

此代码模拟了 GitHub CLI 等工具的工作机制,并适配于 Copilot 场景。关于 GitHub OAuth 的官方文档请参阅 https://docs.github.com/zh/developers/apps/building-oauth-apps/authorizing-oauth-apps#device-flow。如需构建类似功能,请确保符合 OAuth 标准及 GitHub 政策。若对修改或运行此代码有疑问,欢迎咨询!


Back

x-ai/grok-code-fast-1

Donate