htknでGitHub AppのUser Access Tokenを使い、ローカルにシークレットを置かずGitHubと通信する
クライアント端末からGitHub APIを叩くとき、サプライチェーン攻撃対策として、ローカルにシークレットは置きたくないですよね?
そんなときにぴったりなCLIツールが、ghtknです。
ghtknは以下の3つの特徴を備えています。
1. ローカルにトークンを置かない
ghtknはシークレットでないGitHub AppのClient IDだけをローカルに保存します。トークンもプライベートキーも要りません。Gitコミットしても問題ありません。
apps:
- name: my-org/dev
client_id: Ivxxxxxxxxxxxxxxxx
2. 短命のトークンはOSのシークレットマネージャーが管理
ghtknは、GitHub AppのDevice Flowで短命のトークンを発行し、OSのシークレットマネージャー(macOS Keychain / Windows Credential Manager等)に保存します。
しかもトークンは8時間で期限切れになるため、流出リスクが大幅に減ります。
3. 認可はGitHub AppとユーザーのAND
ghtknが利用するUser Access Tokenの権限はユーザーとGitHub AppのANDです。ユーザーに広範な権限があっても、GitHub App側で制限できます。
この仕組みはGitHub AppのUser Access Tokenの仕様であり、ドキュメントでは、次の3項目が明記されています。
- ユーザーがアクセスできるリソースにしかアクセスできない
- Appが権限を持つリソースにしかアクセスできない
- Appがインストールされているアカウントのリソースにしかアクセスできない
ghtknとPATの違い
GitHubのAPI操作でよく使われるPATと比較すると、ghtknの位置づけが分かりやすくなります。
| 観点 | classic PAT | fine-grained PAT | ghtkn (GitHub App User Access Token) |
|---|---|---|---|
| ローカルに置く秘密情報 | トークン本体 | トークン本体 | なし(Client IDのみ) |
| トークンの発行・更新 | ユーザーが手動で発行・再発行 | ユーザーが手動で発行・再発行 | ghtknが自動で取得・リフレッシュ |
| 保管場所 | ユーザー任せ | ユーザー任せ | OSのシークレットマネージャ |
| 有効期限 | 任意(無期限も可) | 任意 | 8時間で失効 |
| 組織側の制御 | 一括許可/ブロックのみ | 承認制・失効管理 | Appの権限・インストールで管理 |
| 権限の絞り込み | ユーザー権限に依存 | トークン単位で細かく指定 | App×ユーザーのANDで制限 |
やってみる
macOSからghtknを使って、GitHub AppのUser Access Tokenを取得し、gh CLIで利用するまでの流れを確認します。
環境
- OS : macOS 26.4.1
- ghtkn : 0.2.5
- gh : 2.93.0
GitHub Appの準備
まずGitHub Appを作成します。組織のSettings > Developer settings > GitHub Appsから新規作成し、以下を設定してください。
- GitHub App name: ユニークな名前
- Expire user authorization tokens: 有効化
- Enable Device Flow: 有効化
- Webhook: 無効化
- Permissions: なし(デフォルトのまま)
- Repository access: なし(デフォルトのまま)
- Where can this GitHub App be installed?: Only on this account(=プライベート)

ghtknのインストール
$ brew install suzuki-shunsuke/ghtkn/ghtkn
$ ghtkn init
$HOME/.config/ghtkn/ghtkn.yamlにGitHub AppのClient IDを記述します。
apps:
- name: my-org/dev
client_id: Ivxxxxxxxxxxxxxxxx
トークン取得からgh CLIでの利用まで
ghtkn 経由でトークンを取得しましょう。初回はブラウザが開きDevice Flowの認可が走ります。
$ ghtkn get
The application uses the device flow to generate your GitHub User Access Token.
Copy your one-time code: XXX-XXXX
This code is valid until 2026-06-23T18:01:51+09:00
Press Enter to open https://github.com/login/device in your browser (it opens automatically after 10 seconds)...
Jun 23 17:47:02.918 INF opened the browser program=ghtkn version=0.2.5 app_name=my-org/dev url=https://github.com/login/device
ghu_xxx
ブラウザから one-time code を入力しましょう。

ghと連携してみましょう。
$ ghtkn get
ghu_XXX
$ REPO=my-org/demo-ghtkn
$ env GH_TOKEN=$(ghtkn get) gh issue create -R "$REPO" --title "Hello, ghtkn" --body "This is created by ghtkn"
Creating issue in my-org/demo-ghtkn
GraphQL: Could not resolve to a Repository with the name 'my-org/demo-ghtkn'. (repository)
初回インストール時に、権限(Permissions)とリポジトリ(Repository)を設定していなかったのが原因です。
権限として IssuesのRead and writeを設定し、操作先リポジトリも設定して再度実行しましょう。
$ env GH_TOKEN=$(ghtkn get) gh issue create -R "$REPO" --title "Hello, ghtkn" --body "This is created by ghtkn"
Creating issue in my-org/demo-ghtkn
https://github.com/my-org/demo-ghtkn/issues/4
今度は成功しました。
このように、最小権限から始めて、足りなければCould not resolve to a Repositoryのようなエラーを手がかりに、権限(Issues: Read and write)と対象リポジトリへのインストールを足していく、という進め方ができます。
ghをghtkn向けにラップする
毎回env GH_TOKEN=$(ghtkn get) gh ...と書くのは面倒です。ラップスクリプトを用意すれば、ghコマンドを直接叩くだけでghtknのトークンが透過的に使われます。
#!/usr/bin/env bash
set -eu
if [ -z "${GH_TOKEN:-}" ] && [ -z "${GITHUB_TOKEN:-}" ]; then
GH_TOKEN="$(ghtkn get)"
export GH_TOKEN
fi
exec /opt/homebrew/bin/gh "$@"
このスクリプトをPATHが通るディレクトリに置き(例: ~/bin/gh)、実行権限(chmod +x ~/bin/gh)を付与してください。
この仕組みにより、ラップスクリプト経由でghコマンドが呼ばれるたびに、ghtknがキャッシュからトークンを取得してGH_TOKENに注入します。
Claude Codeからの呼び出しにも利用できます。
保存されたトークンを確認する(macOS)
トークンはlogin Keychainにgeneric passwordとして、Client IDをキーに保存されます。中身やメタ情報はsecurityコマンドで確認できます。
$ security dump-keychain login.keychain-db | grep -iB2 -A15 ghtkn
class: "genp"
attributes:
0x00000007 <blob>="github.com/suzuki-shunsuke/ghtkn"
0x00000008 <blob>=<NULL>
"acct"<blob>="Ivxxx"
"cdat"<timedate>=0x32303236303631343035333032355A00 "20260614053025Z\000"
...
最後に
GitHubをクライアント環境からAPI操作するとなると、PATがすぐに思いつきますが、GitHub AppのUser Access Tokenを利用しても、シークレットではないClient IDだけをローカル管理して同様のことを実現できます。これをいい感じにラップしたのが、今回ご紹介したghtknです。特に、fine-grained PATのユースケースの多くをカバーできます。
classic PATのように、一つのトークンで何でも操作できず、fine-grained PATと同じく、組織ごとのインストールとなることにご留意ください。
また、ghtknはDevice Flowでユーザー認証するため、CI/CDのような非対話的な用途には使えないことにご注意ください。







