Skip to main content

Using GitHub App Tokens Securely in Harness CI Pipelines

Last updated on

When interacting with GitHub from CI pipelines, authentication is required for actions like creating pull requests, committing code, or accessing private repositories. Traditionally, this was done using static personal access tokens (PATs), but this approach comes with significant drawbacks:

  • Rate limits: User tokens have low rate limits compared to GitHub App installation tokens.
  • Security risks: Hardcoded secrets or token exposure increase your attack surface.
  • User binding: Activity ties to a specific person rather than a system identity.

This guide walks through a modern, flexible solution that uses a GitHub App to generate short-lived tokens at runtime, powered by a Harness-compatible plugin.


Before you begin

  • GitHub App: A registered GitHub App with the specific permissions your pipeline requires (for example, Contents: Read & Write). Go to GitHub's documentation on creating GitHub Apps to register one if you have not already.
  • App installation: The GitHub App must be installed on the target organization or repository. Note the numeric App ID from the app's settings page.
  • Private key: A private key generated for the GitHub App, stored as a file-type secret in Harness. Go to Add file secrets to store the key.
  • Docker connector: A Harness Docker connector that can pull the plugin image from Docker Hub.

Limitations of static tokens and legacy approaches

Earlier approaches involved scripting token generation by manually crafting JWTs, calling GitHub APIs, and injecting tokens into Harness pipelines via a custom secret manager. While functional, this method:

  • Was cumbersome and error-prone.
  • Required external scripts and secret manager setup.
  • Did not work reliably in Harness Cloud, often failing silently or returning incorrect data.

Harness supports a robust and cloud-compatible method using the open source drone-github-app-token plugin.

This plugin generates GitHub App installation tokens securely during pipeline execution. It eliminates the need for PATs or static secrets and enables you to use the token immediately in subsequent steps.

Key benefits:

  • Tokens are ephemeral and scoped to the pipeline execution.
  • Securely injected as output variables.
  • Works in Harness Cloud environments without special configuration.

Example: Use a GitHub App token in a CI pipeline

- step:
identifier: Generate_GitHub_Token
type: Plugin
name: Generate GitHub App Token
spec:
connectorRef: YOUR_DOCKER_CONNECTOR
image: plugins/github-app-token:latest
settings:
app_id: "YOUR_GITHUB_APP_ID"
private_key: <+secrets.getValue("YOUR_GITHUB_APP_KEY")>
permission_contents: write

- step:
identifier: Use_Token
type: Run
name: Use GitHub Token
spec:
shell: Sh
command: |
curl -H "Authorization: token <+execution.steps.Generate_GitHub_Token.output.outputVariables.GITHUB_APP_TOKEN>" \
https://api.github.com/repos/YOUR_ORG/YOUR_REPO/contents
important

The permission_* settings fields must match permissions that your GitHub App was granted during installation. The plugin requests an installation token from GitHub scoped to exactly the permissions you specify. If you pass a permission the app was not granted, the GitHub API rejects the request and token generation fails.

Common permission fields include permission_contents, permission_issues, permission_pull_requests, permission_checks, and permission_statuses. Each accepts a value of read or write. Go to the full permission settings reference below for the complete list.

If you omit all permission_* fields, the token inherits every permission the app installation was granted.

note

The plugin exports several output variables that you can reference in subsequent steps:

<+execution.steps.Generate_GitHub_Token.output.outputVariables.GITHUB_APP_TOKEN>
<+execution.steps.Generate_GitHub_Token.output.outputVariables.GITHUB_APP_INSTALLATION_ID>
<+execution.steps.Generate_GitHub_Token.output.outputVariables.GITHUB_APP_SLUG>

Permission settings reference

You can specify the permissions to grant the generated token. Each permission field corresponds to a GitHub App permission and accepts a value of read or write (some accept admin).

SettingDescription
permission_actionsGitHub Actions workflows, workflow runs, and artifacts
permission_administrationRepository creation, deletion, settings, teams, and collaborators
permission_checksChecks on code
permission_codespacesCreate, edit, delete, and list Codespaces
permission_contentsRepository contents, commits, branches, downloads, releases, and merges
permission_dependabot_secretsManage Dependabot secrets
permission_deploymentsDeployments and deployment statuses
permission_environmentsManage repository environments
permission_issuesIssues and related comments, assignees, labels, and milestones
permission_membersOrganization teams and members
permission_metadataSearch repositories, list collaborators, and access repository metadata
permission_packagesPackages published to GitHub Packages
permission_pagesRetrieve Pages statuses, configuration, and builds
permission_pull_requestsPull requests and related comments, assignees, labels, milestones, and merges
permission_repository_hooksManage the post-receive hooks for a repository
permission_secret_scanning_alertsView and manage secret scanning alerts
permission_secretsManage repository secrets
permission_security_eventsView and manage security events like code scanning alerts
permission_statusesCommit statuses
permission_vulnerability_alertsManage Dependabot alerts
permission_workflowsUpdate GitHub Actions workflow files
tip

For the complete list including organization-level permissions, go to the plugin repository README.


Best practices

  • Store the GitHub App private key as a Harness file secret. Do not inline private key content in pipeline YAML.
  • Use scoped permissions on your GitHub App and reflect only the required permissions in the plugin's permission_* settings fields. The plugin requests only what you explicitly pass, so follow the principle of least privilege in both places.
  • Pass the generated token only between pipeline steps. Do not log or persist it.