ghtkn

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2025 License: MIT

README ΒΆ

ghtkn

License | Install | Usage

ghtkn is a CLI that generates User Access Tokens from GitHub Apps using Device Flow.

Unlike Installation Access Tokens, User Access Tokens are attributed to users, allowing operations to be performed as the user. For details, please refer to the official documentation.

Users can perform arbitrary operations using access tokens generated by ghtkn. ghtkn allows you to manage multiple GitHub Apps through configuration files and manage access tokens using secret managers like Windows Credential Manger, macOS KeyChain, or GNOME Keyring.

[!WARNING] With Device Flow, access tokens cannot be generated in non-interactive environments like CI. ghtkn is primarily intended for local development.

Why ghtkn is needed

By using ghtkn, you can minimize the risk of access token leakage in local development and enhance security. Keeping long-lived access tokens like GitHub CLI OAuth App tokens or Personal Access Tokens locally poses a significant risk if they are leaked. ghtkn doesn't require highly sensitive secrets like Personal Access Tokens, GitHub App Private Keys, or Client Secrets. All that's needed is the GitHub App's Client ID, and User Access Tokens only have an 8-hour validity period, making them relatively safer.

[!NOTE]
Ideally, we would like to generate shorter-lived tokens of about 1 hour, but this doesn't seem to be possible.

πŸš€ Getting Started

[!WARNING] As a prerequisite, Windows Credential Manager, macOS KeyChain, or GNOME Keyring is required. It will work without them, but in that case, you'll need to generate access tokens every time.

First, install ghtkn. Then create a GitHub App with issues:write permission (This permission is just an example). Generate a configuration file at ${XDG_CONFIG_HOME:-${HOME}/.config}/ghtkn/ghtkn.yaml with ghtkn init and modify it.

persist: true # false if Windows Credential Manager, macOS KeyChain, or GNOME Keyring is not available
apps:
  - name: suzuki-shunsuke/write # Required. GitHub App identifier. Not the App ID, freely configurable by the user but must be unique
    client_id: xxx # Required. GitHub App Client ID
    default: true # Optional. Only one app in apps can be true. The true app is used by default

[!NOTE]
The GitHub App Client ID is not a secret, so there's generally no problem writing it in plain text in local configuration files.

In this state, run ghtkn get to generate an access token and try running gh issue create.

env GH_TOKEN=$(ghtkn get) gh issue create -R "<your repository>" --title "Hello, ghtkn" --body "This is created by ghtkn"

https://github.com/login/device will open in your browser, so enter the code displayed in the terminal and approve it. Then an access token will be generated and the issue will be created successfully. At this time, the issue creator will be you, not the App. You can close the opened tab.

If you run the same command immediately, it will now run without the authorization flow (if persist: false, the authorization flow runs every time).

πŸ’‘ Wrapping arbitrary commands with ghtkn

You can write simple wrappers (shell functions) for arbitrary commands that require access tokens using ghtkn.

e.g.

gh() {
    env GH_TOKEN=$(ghtkn get) command gh "$@" # Be careful to use 'command' to avoid infinite loops
}

This way, when you run the gh command normally, the access token will be automatically passed to the gh command.

Specifying an App

You can configure multiple GitHub Apps in the apps section of the configuration file and create and use different Apps for each Organization or User. You can specify the App when running ghtkn.

e.g.

ghtkn get suzuki-shunsuke/write

Alternatively, you can specify it with the environment variable GHTKN_APP. For example, it might be convenient to switch GHTKN_APP for each directory using direnv.

By default, the one with default: true is used. If there's no default: true, the first App in apps is used.

Access Token Regeneration

ghtkn stores generated access tokens and their expiration dates in the secret manager. ghtkn get retrieves these, and if the expiration has passed, regenerates the access token through Device Flow. The access token validity period is 8 hours.

By default, if the access token hasn't expired, it returns it, but this may result in a short-lived access token being returned. By specifying -min-expiration (-m) <minimum required validity period. Not a datetime but remaining time>, the access token will be regenerated if its validity period is shorter than the specified duration.

ghtkn get -m 1h

2h, 30m, 30s etc. are also valid. Units are required.

Creating GitHub Apps

Create one or two GitHub Apps for each Organization and User you manage.

  • Check Enable Device Flow
  • Uncheck Webhook

When creating multiple Apps for the same Organization and User, vary the Permissions and Repositories according to their purpose. Unlike Installation Access Tokens, you cannot narrow permissions when generating tokens. Therefore, you cannot use an App with strong permissions to generate a token with weak permissions, so create Apps with weak permissions as well as strong permissions according to your needs.

The granularity depends on the individual. To avoid overly complex management, for example:

  1. No Permission: One is enough
  2. read-only (installed on all repos): One per Org and User
  3. write (installed on all repos): One per Org and User

It's safer to use tokens without permissions by default.

persist: true
apps:
  - name: suzuki-shunsuke/read
    client_id: xxx1
  - name: suzuki-shunsuke/write
    client_id: xxx2
  - name: aquaprj/read
    client_id: xxx3
  - name: aquaprj/write
    client_id: xxx4
  - name: none
    client_id: xxx5
    default: true
GitHub App with no permissions

While no permissions are needed to read Public Repositories, without an access token, you're likely to hit API rate limits. In such cases, it's convenient to be able to generate an access token with no permissions. So, create a GitHub App with no permissions. You don't need to install the App either.

Configuration file path

[!WARNING] The file extension .yml isn't supported as there is no reason to support it. Please use .yaml.

  1. -c option
  2. $GHTKN_CONFIG
  3. (macOS, Linux) ${XDG_CONFIG_HOME}/ghtkn/ghtkn.yaml
  4. (macOS, Linux) ${HOME}/.config/ghtkn/ghtkn.yaml
  5. (Windows) %APPDATA%\ghtkn\ghtkn.yaml

Environment Variables

All environment variables are optional.

  • GHTKN_LOG_LEVEL: Log level. One of debug, info (default), warn, error.
  • GHTKN_OUTPUT_FORMAT: The output format of ghtkn get command
    • json: JSON Format
  • GHTKN_APP: The app identifier to get an access token
  • GHTKN_MIN_EXPIRATION: The minimum expiration duration of access token. If ghtkn get gets the access token from keying but the expiration duration is shorter than the minimum expiratino duration, ghtkn get creates a new access token via Device Flow
  • GHTKN_CONFIG: The configuration file path
  • XDG_CONFIG_HOME

Comparison between GitHub App User Access Token and other access tokens

GitHub CLI OAuth App access token

https://cli.github.com/manual/gh_auth_token

This can be easily generated with gh auth login, gh auth token in GitHub CLI. You don't need to generate Personal Access Tokens, and it's convenient. Also, when scopes across Users or Organizations are needed, it's difficult with non-Public GitHub Apps, but installing GitHub CLI OAuth App across multiple Users or Organizations solves such problems.

However, this access token is not very good from a security perspective. While you can restrict the scope (permission) and target Organizations, these tend to be quite broad for convenience. Also, it's basically indefinite. Therefore, the risk when this token is leaked is very high.

So, a more secure mechanism is needed.

fine-grained Personal Access Token

https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens

We'll ignore Legacy PAT as it's almost the same as OAuth App tokens.

Fine-grained access tokens have the following disadvantages compared to User Access Tokens:

  • Regular rotation is cumbersome
  • Management is cumbersome
  • High risk when leaked
    • While the validity period is not indefinite, it tends to be quite long
      • Since short periods make rotation cumbersome, it tends to be 1 year or 6 months
      • Not on the order of a few hours
GitHub App installation access token

https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation

  • Pros
    • Can change permissions, repositories, and validity period when generating tokens
  • Cons
    • Cannot operate as a User
      • e.g., PR creator becomes the App
    • Private Key management is cumbersome
    • High risk when Private Key is leaked

πŸ“ Note

API rate limit

https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#primary-rate-limit-for-github-app-installations

Primary rate limits for GitHub App user access tokens (as opposed to installation access tokens) are dictated by the primary rate limits for the authenticated user. This rate limit is combined with any requests that another GitHub App or OAuth app makes on that user's behalf and any requests that the user makes with a personal access token. For more information, see Rate limits for the REST API.

The rate limit for authenticated users is 5,000 per hour, so it should be fine for normal use.

All of these requests count towards your personal rate limit of 5,000 requests per hour.

⚠ Limitation

ghtkn doesn't support some operations that require Client Secrets as the risk of Client Secret leakage is high:

Instead, if the validity has expired, the access token is regenerated through Device Flow.

LICENSE

MIT

Directories ΒΆ

Path Synopsis
cmd
gen-jsonschema command
ghtkn command
pkg
apptoken
Package apptoken handles GitHub App access token generation using OAuth device flow.
Package apptoken handles GitHub App access token generation using OAuth device flow.
cli
Package cli provides the command-line interface layer for ghtkn.
Package cli provides the command-line interface layer for ghtkn.
cli/flag
Package flag provides common command-line flags for ghtkn CLI.
Package flag provides common command-line flags for ghtkn CLI.
cli/get
Package get implements the 'ghtkn get' command.
Package get implements the 'ghtkn get' command.
cli/initcmd
Package initcmd implements the 'ghtkn init' command.
Package initcmd implements the 'ghtkn init' command.
config
Package config provides configuration management for ghtkn.
Package config provides configuration management for ghtkn.
controller/get
Package get provides functionality to retrieve GitHub App access tokens.
Package get provides functionality to retrieve GitHub App access tokens.
controller/initcmd
Package initcmd implements the business logic for the 'ghtkn init' command.
Package initcmd implements the business logic for the 'ghtkn init' command.
keyring
Package keyring provides secure storage for GitHub access tokens.
Package keyring provides secure storage for GitHub access tokens.
log
Package log provides structured logging functionality for ghtkn.
Package log provides structured logging functionality for ghtkn.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL