How to Use actions/checkout with Private Repositories: Authentication Methods Explained

Yes, actions/checkout fully supports private repositories, but you must configure authentication using the default GITHUB_TOKEN for the same repository, a Personal Access Token (PAT) for different repositories, or an SSH key for secure Git operations.

The actions/checkout action is the standard way to clone repositories in GitHub Actions workflows. When working with private repositories, the action handles authentication securely through multiple methods depending on whether you're accessing the workflow's own repository or an external one.

Authentication Scenarios for Private Repositories

Checkout the Same Private Repository (Automatic)

When your workflow runs in a private repository and you need to checkout that same repository, actions/checkout works out-of-the-box. The action automatically uses the default ${{ github.token }} (the GITHUB_TOKEN provided to the workflow), which is scoped to the repository that owns the workflow.

In src/input-helper.ts (lines 39-41), the token input defaults to the workflow's GITHUB_TOKEN, allowing immediate read access without extra configuration:

- uses: actions/checkout@v7
  # No extra inputs – the default GITHUB_TOKEN suffices

Checkout a Different Private Repository (PAT Required)

To checkout a private repository different from the one triggering the workflow, you must supply a Personal Access Token (PAT) with appropriate repository permissions. Pass the token via the token input, which the action injects as an HTTP header for Git operations.

According to the README.md (line 291), the PAT requires repo scope (or finer-grained permissions) for the target repository:

- uses: actions/checkout@v7
  with:
    repository: my-org/my-private-tools   # owner/repo of the private repo

    token: ${{ secrets.MY_PAT }}          # PAT with appropriate repo scopes

    path: tools                           # optional, where to place the repo

SSH Authentication

For environments requiring SSH-based authentication, provide an SSH private key via the ssh-key input. You can optionally specify known hosts via ssh-known-hosts to prevent man-in-the-middle attacks.

In src/input-helper.ts (lines 42-48), the action handles sshKey and sshKnownHosts inputs, adding the key to the Git config and removing it after the job completes:

- uses: actions/checkout@v7
  with:
    repository: my-org/my-ssh-repo
    ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}   # SSH private key

    ssh-known-hosts: |
      github.com ssh-rsa AAAAB3Nza...
    ssh-strict: true                         # optional, enforce host-key checking

How Authentication Works Under the Hood

The action implements secure credential handling through two key components:

Input Processing – The getInputs() function in src/input-helper.ts parses workflow inputs (token, ssh-key, repository, etc.) and builds an IGitSourceSettings object that drives the checkout flow. The repository input defaults to ${{ github.repository }}, but when a different owner/repo is supplied, the action uses the provided token or SSH key to authenticate against the target host.

Authentication Configuration – The src/git-auth-helper.ts file creates temporary credentials for the Git operation. For token-based auth, it creates a temporary .extraheader entry using the format x-access-token:<token>. For SSH authentication, it configures a temporary SSH credential file. Both methods are removed in the post-step to prevent credential leakage.

Practical Code Examples

Checkout Multiple Private Repositories Side-by-Side

You can checkout multiple private repositories within the same job by specifying different paths and authentication tokens:

- name: Primary repo (public or private)
  uses: actions/checkout@v7
  with:
    path: main

- name: Secondary private repo
  uses: actions/checkout@v7
  with:
    repository: my-org/second-private
    token: ${{ secrets.SECOND_PAT }}
    path: second

Complete SSH Configuration

When using SSH authentication, ensure you provide the private key in the correct format and specify known hosts when ssh-strict is enabled:

- uses: actions/checkout@v7
  with:
    repository: my-org/private-repo
    ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
    ssh-known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }}
    ssh-strict: true

Summary

  • Same repository checkout: Uses the default GITHUB_TOKEN automatically via src/input-helper.ts (lines 39-41) with no additional configuration required.
  • Different repository checkout: Requires a PAT passed via the token input with appropriate repository scopes.
  • SSH authentication: Supported via ssh-key and ssh-known-hosts inputs, handled securely in src/input-helper.ts (lines 42-48) and cleaned up post-job.
  • Security: Credentials are temporarily injected by git-auth-helper.ts and removed after checkout to prevent leakage on self-hosted runners.

Frequently Asked Questions

Does actions/checkout work with private repositories without any configuration?

Yes, but only for the repository that triggered the workflow. The default GITHUB_TOKEN provided to the workflow run automatically authenticates access to the same private repository. For any other private repository, you must explicitly provide a PAT or SSH key.

Why do I need a PAT for a different private repository when I already have GITHUB_TOKEN?

The GITHUB_TOKEN is scoped only to the repository where the workflow runs. When you need to access a different private repository (cross-repository access), GitHub's security model requires explicit authorization through a PAT that has been granted access to the target repository.

Is the SSH key or token stored permanently on the runner?

No. According to the implementation in src/git-auth-helper.ts, the action creates temporary credential configurations (HTTP headers or SSH files) for the duration of the job only. The post-job cleanup step removes these credentials to prevent exposure on self-hosted runners or subsequent workflow runs.

Can I checkout multiple private repositories in one job?

Yes. You can invoke actions/checkout multiple times within the same job, specifying different repository names, path locations, and authentication tokens. Each invocation operates independently, allowing you to clone several private repositories side-by-side using different PATs if needed.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →