If you’re a developer using Github and working with CI/CD pipelines or custom tooling, chances are you’ve used Personal Access Tokens (PATs) to interact with GitHub. They’re simple and get the job done - but they also come with serious downsides: over-permissioned access, long-lived credentials, limited visibility, and no clear separation between user and automation; even if you are using a service user for your automation, there’s still downsides to it.
The good news? GitHub Apps are now a mature alternative which is both safer and scalable. Designed specifically for automation, they provide fine-grained permissions, short-lived tokens, and a clear identity for your tooling — so your scripts and bots stop pretending to be you. Whether you’re maintaining open source projects or deploying enterprise software, you can now move away from PATs and build your tooling on something better. Let’s look at the reasoning and a simple example to show how to use Github Apps in CI/CD workflows!
Personal Access Tokens (PATs) & Github Apps
PATs are a way to authenticate to GitHub on behalf of a user, allowing access to the GitHub API or perform Git operations. They function like passwords and are tied directly to an user account. When used, a PAT grants access to the resources and repositories that the user has permissions for.
GitHub offers two types of PATs:
Classic PATs are the older option; they provide broad access to an user’s account based on generic scopes. While easier to set up, it is harder or impossible to limit their access to specific repositories or permissions. Github organizations can block the usage of such tokens too, limiting their usage.
Fine-Grained PATs are a more secure alternative, allowing their access to be limited to specific repositories and permissions. Github organizations can limit, review and audit this type of token, increasing auditibility and visibility of their use.
Even with the security improvements when using Fine-Grained PATs, both types are still tied to a user identity - meaning automation that uses them to impersonate a person. Another concern is their token: long-lived and hard to rotate, a risk if it is leaked. A lot of improvements have been done to PATs, but they are still difficult to scope precisely, to identify their ownership and trace their usage.

Setting up a classic PAT
GitHub Apps are the alternative designed to provide a way of building integrations and automating workflows within the GitHub ecosystem. Unlike PATs, GitHub Apps have their own identity and authenticate using short-lived tokens. This allows them to act as standalone entities with precisely scoped permissions and limited access to repositories. They can be installed from individual repositories, to entire organizations, and even across organizations, making them highly flexible for everything from CI/CD pipelines to custom bots and internal tools. They also provide better auditability, as all actions taken by the app are clearly logged as coming from the app itself and not an user.
GitHub Apps also offer significantly higher API rate limits compared to Personal Access Tokens. While PATs are restricted to 5,000 requests per hour per user, GitHub Apps can make up to 15,000 requests per hour per installation. For GitHub Enterprise customers, this limit is even higher - 15,000 requests per repository per hour. This substantial increase in throughput is especially valuable in high-volume CI/CD environments, where automated processes can quickly hit API limits due to frequent builds, deployments, and status checks. Relying on PATs in such scenarios can lead to throttling, delays, and operational bottlenecks—issues that GitHub Apps are far better equipped to handle.
Feature / Capability | Classic PATs | Fine-Grained PATs | GitHub Apps |
---|---|---|---|
Identity | Tied to a user account | Tied to a user account | Independent app identity |
Permission Scope | Broad scopes (e.g., repo , admin:org ) | Narrow, repository or account specific, action-based scopes | Highly granular, repo/org-level per permission |
Token Lifetime | Long-lived (optional expiration feature added) | Long-lived (with optional expiration) | Short-lived (1 hour) tokens |
Authentication Model | Static token | Static token | JWT + short-lived access token |
Audit Clarity | Appears as the user | Appears as the user | Clearly shown as app activity |
Repository Access Control | All user-accessible repos | Specific repos chosen at token creation | Installable per repo or org |
API Rate Limit | 5,000 req/hr per user | 5,000 req/hr per user | 15,000 req/hr per app installation |
Token Rotation | Manual | Manual | Automated / programmatic |
Risk of Overexposure | High (broad, static access) | Medium (scoped but still user-based) | Low (scoped, short-lived, app-isolated) |
Recommended For | Legacy scripts, simple tools | Manually controlled automation, limited scope | CI/CD, bots, secure integrations |
User Dependency | Yes | Yes | No (user-independent) |
Using Github Apps - an example
For this example, we will look at a simple (but one of the most common!) use cases for using PATs: committing changes to a repository. We will be creating and running a Github workflow that uses a Github App to commit to a different repository.
To start, have a github user account, and create two repositories, for example:
gitapp_source
and gitapp_destination
. Make sure the destination repository has at least
one commit (so that refs/heads/main
is present for this example to work).
Setting up the Github App
Create a new Github App
Let’s start by creating a Github App. Go to your user Settings -> Under Developer Settings and under Github Apps, click New Github App.
Github Apps can be owned by Users or Organizations. For Organization owned Apps, go to the Organization Developer Settings instead. Organization Github Apps can have administrator users assigned!Fill the mandatory fields
GitHub App name
andHomepage URL
. Disable the Webhook option for events, and under permissions, click Repository Permissions and toggle the Contents access to Read and write; this will grant the Application full source code access in the repositories it gets installed to.Scroll down and click Create Github App. You will be redirected to the newly create Github App’s page. Take note of the App ID number, we will need it later!
Generate a Github App private key
Now the application is created, we need to generate a Private key, used to assume the Github App.
In the Github App page, scroll down to the
Private Keys
section. Click Generate a new Private Key, and save it in a safe location.Installing the Github App
Let’s install our Github App in the destination repository.
On the left hand side, click on the Install App page, choose the account of the destination repository and click Install.
Installing a Github App
Github will now ask you which repositories you want to install the App; by default it installs for all repositories. Following best practices, we select Only selected repositories, choose the previously created destination repository and click Install. Notice the list the permissions that we are granting*.
Github App repository instalation
And we are done for the Github App! You should have the App ID and the generated Private key required for the next steps.
Github Actions environment variables
We will be assuming the Github App identity from the source repository to write into the destination repository. Let’s configure the Github Actions variables and secrets in the source repository with the required values.
Under the source repository Settings, go to Secrets And Variables and click Actions.
In the Secrets tab, click New Repository Secret, set the name to
PRIVATE_KEY
and the copy the content of the key file that you downloaded in the previous steps to the value field.Click Add Secret.
Now go to the Variables tab and create the following repository variables: Name: APP_ID Value: the app id you saved in the previous steps (Example:
1394137
)Name: TARGET_REPOSITORY Value: the target repository name, in our example
gitapp_example_destination
You should now have under Secrets tab the PRIVATE_KEY
, and under the Variables tab APP_ID
and TARGET _REPOSITORY
.
Github workflow using a Github App
The only piece missing is the github action workflow! In the source repository, create and commit the following workflow (.github/workflows/createCommit.yml).
name: Create file & commit to another repo
on: workflow_dispatch
jobs:
create_and_build:
name: Create & Save
runs-on: ubuntu-latest
steps:
# Generate a temporary token for this run
- name: Generate token
uses: actions/create-github-app-token@v1.11.1
id: app-token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ vars.TARGET_REPOSITORY }}
# Checkout the target repository
- name: Set/get environment from checkout
uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
repository: ${{ github.repository_owner }}/${{ vars.TARGET_REPOSITORY }}
path: target_repo
# Create file
- name: Push code
run: |
echo "Hello from ${{ github.action_repository }} run ${{ github.run_id }}" > target_repo/hello.txt
# Commit and Push
- name: Push code
run: |
cd target_repo
git config user.name github-actions
git config user.email github-actions@github.com
git add .
git commit -m "Update run ${{ github.run_id }}"
git push
Go to the actions -> workflows for the source repository and manually trigger a run:
Once the workflow finishes, you should see a new file in the destination repository!
Conclusion
GitHub Apps provide a secure, scalable, and modern alternative to Personal Access Tokens (PATs). They authenticate with their own identities, and can be set up with granular and repository level permissions. Their tokens are short-lived, and enable the Centralized revocation and rotation of credentials. Because Apps can target only the repos that need them, blast radius shrinks dramatically compared with PATs that inherit a user’s full access. And by tying automation to a dedicated app rather than individual employees, we can make our CI more resilient, avoiding risks and paying an extra user license for every bot account.
Moreover a single GitHub App can be installed on dozens of repositories and organizations without multiplying credentials, making it perfect for multi‑tenant SaaS integrations. You can even list it on the GitHub Marketplace to reach new customers, something PATs can’t offer.
Hopefully with this example you understand Github Apps a bit better, and can take steps to make your platform more secure, manageable and built to scale with your use cases.