Service Accounts

This public content is an excerpt from Flutter staff GitHub docs. It is published as a reference to show how GitHub is used for inner source at Flutter.

To use GitHub APIs from your own automation you need one of:

  1. GitHub Action Token – a short-lived access token available to GitHub Action workflows.
  2. Deploy Key – an SSH key with read or write access to a single repository.
  3. GitHub App – to generate short-lived access tokens with limited permissions on-demand.
  4. Your Fine-Grained Access Token – your access token but with limited permissions & scope.
  5. Machine User Access Token – an access token for a GitHub account with limited permissions.

Attempt these options in this order – i.e. only consider (2) if (1) isn’t suitable; only consider (3) if (2) isn’t suitable, etc.


You must:

  1. Least Privilege: Configure the minimum access possible – limited permissions, on limited repositories, for a limited time.
  2. Transport & Storage: Store and transport the credentials securely. Use mechanisms approved by your divisional security team for in-house systems. For 3rd parties, their security assessment score must be low risk.
  3. Ownership: Document who owns and supports the integration.
  4. Access & Rotation: Rotate credentials and review privileges at least once every year.
  5. Ease of Use: Optimise for ease of use not just reduced risk.

Example: Jenkins

A Jenkins instance requires read access to a set of repositories in Flutter-Global for CI/CD.

  1. ❌ A GitHub Action Workflow Token isn’t available outside a workflow.
  2. ❌ A Deploy Key can only provide access to one repository.
  3. ✅ A GitHub App can provide read-only access to specific content.

A GitHub App meets the requirements because:

  • Least Privilege: The GitHub App limits permission to read-only access to specific repos.
  • Transport & Storage: Jenkins stores the app private key in Jenkins Credentials, and uses short-lived access keys & SSL to access GitHub APIs.
  • Ownership: Flutter-Global org owners document the justification for the app and the contact details of the team who support Jenkins.
  • Access & Rotation: Org owners create a reminder for an annual private key rotation and access permission review.
  • Ease of Use: The app has read access to all inner source repositories by default. This reduces the effort of repo access additions, but is low-risk given the intended wide visibility of these repos already.

GitHub Action Token

A GitHub Action workflow can use an automatic access token provided in the GITHUB_TOKEN environment variable. GitHub document this here.

For read access to other repositories, in Flutter-Global you can use the pre-configured cross repo read access to clone another inner source repository.

Deploy Key

A deploy key is an SSH key granted read or write access to the content of a single repository.

  • You can create one yourself.
  • Use a read-only deploy key to clone a repo and use the content.
  • Use a write deploy key to commit changes to the content. This write is an “admin” commit so can bypass branch protection if configured to do so.
How to use a deploy key in a GitHub Action workflow.
- name: Setup SSH agent to use deploy key
    SSH_AUTH_SOCK: /tmp/ssh_agent.sock
    SSH_PRIVATE_KEY: ${{ secrets.MY_DEPLOY_KEY }}
  run: |
    ssh-agent -a $SSH_AUTH_SOCK > /dev/null
    ssh-add - <<< "$SSH_PRIVATE_KEY"
- name: Checkout the repo using deploy key
    SSH_AUTH_SOCK: /tmp/ssh_agent.sock
  run: git clone --depth 1 my-repo
# ...
# make any changes required (if a write use-case)
# ...
- name: Push repo changes using deploy key
  working-directory: my-repo
    SSH_AUTH_SOCK: /tmp/ssh_agent.sock
  run: |
    if [ ! -z "$(git status --porcelain=v1 2>/dev/null)" ]
      git config "github-actions"
      git config
      git pull --no-edit
      git add -A
      git commit -m 'my commit message'
      git push

A deploy key can be securely stored in GitHub secrets for use in a workflow.

GitHub App

GitHub Apps can generate short-lived access tokens on-demand. An app has permissions and scope settings the same as a fine-grained access token which is useful to test with first.

- uses: actions/create-github-app-token@v1
  id: app-token
    app-id: ${{ vars.APP_ID }}
    private-key: ${{ secrets.PRIVATE_KEY }}

Always protect the token in a GitHub environment to use it in a GitHub Action workflow.

Your Fine-Grained Access Token

A fine-grained personal access token represents your GitHub account with restricted scope (i.e. limited repositories) and restricted permissions (i.e. what it can do). At present this is a beta product from GitHub – everything works OK apart from these tokens can’t authenticate with GitHub Packages.

A common question is:

Isn’t this fragile/bad? What if I leave or change roles?

A personal fine-grained access token is less robust than a GitHub App, but for minor point-to-point automation often more convenient. The ability to limit the scope and permissions means you aren’t leaking your other account permissions. Yes, you need to change the ownership of the token if you leave or change role – but you need to rotate these tokens regularly anyway. We recommend a short token expiry (e.g. 3 months) so that you are regularly reminded of it exists and make you more likely to document it!

⚠️ Don’t confuse “FINE-GRAINED” access tokens with “CLASSIC” personal access tokens. Classic access tokens have no restrictions on scope (which repositories) and only crude permissions (i.e. the what it can do). If you need to use a classic access token, you must use a machine user (see below) to limit the scope and permissions via that user.

Machine User

A machine user is a GitHub account used exclusively for system automation. You use it by creating fine-grained or classic access tokens for the user.