CLIアプリケーション向けGitHub OAuth 2.0

デバイスコードフローを使用したコマンドラインツールでのGitHub OAuth 2.0認証の実装。完全なフローウォークスルー付き。

Real-World Flows

詳細な説明

CLI向けGitHub OAuth 2.0

GitHubはデバイスコードフローをサポートしており、ユーザーが直接資格情報を入力できないCLIアプリケーションに最適です。CLIがコードとURLを表示し、ユーザーがブラウザで認証すると、CLIがトークンを受信します。

GitHub OAuthエンドポイント

エンドポイント URL
デバイス認可 https://github.com/login/device/code
トークン https://github.com/login/oauth/access_token
ユーザーAPI https://api.github.com/user

ステップ1:GitHub OAuthアプリを作成

  1. GitHubの設定 > 開発者設定 > OAuthアプリに移動
  2. 新しいアプリケーションを登録
  3. 注意:GitHub OAuthアプリはデバイスフローにclient_secretの要件がない
  4. client_idを保存

ステップ2:デバイスコードをリクエスト

curl -X POST https://github.com/login/device/code \
  -H "Accept: application/json" \
  -d "client_id=YOUR_CLIENT_ID&scope=repo%20user"

レスポンス:

{
  "device_code": "3584d83530557fdd1f46af8289938c8ef79f9dc5",
  "user_code": "WDJB-MJHT",
  "verification_uri": "https://github.com/login/device",
  "expires_in": 899,
  "interval": 5
}

ステップ3:ユーザーに表示

! まずワンタイムコードをコピー: WDJB-MJHT
- Enterキーを押してブラウザでgithub.comを開きます...

ステップ4:トークンをポーリング

curl -X POST https://github.com/login/oauth/access_token \
  -H "Accept: application/json" \
  -d "client_id=YOUR_CLIENT_ID\
  &device_code=3584d83530557fdd1f46af8289938c8ef79f9dc5\
  &grant_type=urn:ietf:params:oauth:grant-type:device_code"

保留中のレスポンス:{"error": "authorization_pending"}

成功レスポンス:

{
  "access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a",
  "token_type": "bearer",
  "scope": "repo,user"
}

ステップ5:トークンを使用

curl -H "Authorization: Bearer gho_16C7e42F292c6912E7710c838347Ae178B4a" \
  https://api.github.com/user

Node.js実装

const open = require("open");

async function githubDeviceAuth(clientId) {
  // ステップ1: デバイスコードを取得
  const codeRes = await fetch("https://github.com/login/device/code", {
    method: "POST",
    headers: {
      "Accept": "application/json",
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: `client_id=${clientId}&scope=repo user`,
  }).then(r => r.json());

  console.log(`コードを入力: ${codeRes.user_code}`);
  await open(codeRes.verification_uri);

  // ステップ2: トークンをポーリング
  while (true) {
    await new Promise(r => setTimeout(r, codeRes.interval * 1000));
    const tokenRes = await fetch(
      "https://github.com/login/oauth/access_token",
      {
        method: "POST",
        headers: {
          "Accept": "application/json",
          "Content-Type": "application/x-www-form-urlencoded",
        },
        body: `client_id=${clientId}&device_code=${codeRes.device_code}&grant_type=urn:ietf:params:oauth:grant-type:device_code`,
      }
    ).then(r => r.json());

    if (tokenRes.access_token) return tokenRes.access_token;
    if (tokenRes.error === "authorization_pending") continue;
    throw new Error(tokenRes.error_description || tokenRes.error);
  }
}

一般的なGitHubスコープ

スコープ アクセス
repo プライベートリポジトリの完全な制御
repo:status コミットステータスの読み書き
user ユーザープロフィールデータの読み取り
read:org 組織メンバーシップの読み取り
gist Gistの作成
workflow GitHub Actionsワークフローの更新

ユースケース

GitHubで認証する必要があるCLIツール(GitHub CLI、Terraform、カスタムデプロイツールなど)の構築。デバイスコードフローにより、ターミナルにトークンを貼り付けることなくブラウザで安全に認証できます。

試してみる — OAuth 2.0 Flow Visualizer

フルツールを開く