Git Course 0%

Tokens, SSH keys, security settings

Intermediate GitHub UI ≈ 8 min

What you will learn

  • Which GitHub credential to use for which job, and where each is created
  • Why fine-grained tokens are the default choice now
  • Where a repository keeps the secrets its workflows use

After this lesson you can

  • I can create the least powerful credential that does the job, and clean up the rest

Why this matters

Section 8 covered what tokens and keys are. This is the map: which of GitHub's credential types to reach for, and the exact page each lives on. It is the difference between "I made a token" and "I made a token that can read one repository and expires in ninety days".

The choice, in one table

Pick the least powerful thing that works.

You want to Use Created at
Push and pull over HTTPS as yourself Fine-grained personal access token, Contents: read and write Profile photo → SettingsDeveloper settingsPersonal access tokensFine-grained tokens
Push and pull over SSH as yourself SSH key SettingsSSH and GPG keys
Let a server read or write one repository Deploy key Repository SettingsDeploy keys
Give a workflow a secret Actions secret Repository SettingsSecrets and variablesActions
Let an integration act on its own GitHub App, usually installed rather than built Organization SettingsGitHub Apps
Sign your commits GPG or SSH signing key SettingsSSH and GPG keys

Two rules follow. Never use your personal token for automation: it carries your access, it dies when you leave, and its actions look like yours. And never put a credential in the repository: that is what Actions secrets are for (lesson 8.6).

Fine-grained versus classic tokens

GitHub has two kinds of personal access token, and the newer one is better in every way that matters:

Fine-grained Classic
Reaches One account or organization's resources, and only the repositories you select Every repository you can access, everywhere
Permissions Specific: Contents, Issues, Pull requests, each read or write Broad scopes such as repo
Organization control Owners can require approval before it works on their repositories None
Use it when Always, unless something you need is unsupported The rare feature fine-grained tokens do not cover yet

For Git over HTTPS, a fine-grained token needs Contents: Read and write on the repositories you choose. That is the whole permission. Tools that read issues and pull requests, such as the VS Code and IntelliJ integrations, need a little more.

Set an expiry you can live with. Infinite lifetimes are allowed, and organizations may forbid them; either way, a token nobody remembers is a token nobody revokes. GitHub emails you before one expires, and that email is your only warning.

The token value is shown once. If you did not copy it, delete it and make another.

SSH keys and deploy keys

An SSH key on your account authenticates you everywhere you have access (lesson 8.2). A deploy key is an SSH key added to one repository, read-only unless you tick write access, and belonging to no person. For a build server that clones one repository, a read-only deploy key is the correct answer and a personal token is not.

A key can be added as a signing key as well as an authentication key, which is how commits get the "Verified" badge (lesson 8.8).

Secrets for workflows

Settings → Secrets and variables → Actions holds two lists: Secrets, which are hidden after saving and redacted from logs, and Variables, which are not secret and are readable in the interface. Environment-scoped secrets live under Settings → Environments, where they can be gated behind a required reviewer.

Three facts a contributor should know:

  • Secrets are redacted from logs, but a value transformed before printing, such as base64-encoded, will not be caught.
  • Secrets are not passed to workflows triggered by a pull request from a fork, which is why some checks skip on fork contributions.
  • Anyone who can edit a workflow file can make it use what it can read, which is why workflow changes deserve careful review.

The GITHUB_TOKEN is different: GitHub creates it automatically for each run, it expires when the job ends, and its permissions are set in the workflow. It is the right credential for a workflow acting on its own repository, and it needs no setup from you.

Reviewing what you have

Every few months, or the day someone leaves:

  1. Settings → Developer settings → Personal access tokens: delete what you cannot explain; note what expires soon.
  2. Settings → SSH and GPG keys: remove keys for machines you no longer have.
  3. Settings → Sessions and Security log: check where your account has been used.
  4. Repository Settings → Deploy keys: remove keys for retired systems.
  5. Repository Settings → Secrets and variables: confirm nothing secret is sitting in Variables.
  6. Organization Settings → Personal access tokens to review or revoke fine-grained tokens that reach the organization.

Revoking is instant and the only cost is creating a new credential, which is the right trade.

How to do it

Two checks tell you which credential your clone actually uses:

Terminal
$ git remote -v
origin	git@github.com:northwind-trails/trailguide.git (fetch)
origin	git@github.com:northwind-trails/trailguide.git (push)

A git@ address uses your SSH key; an https:// address uses a token from the credential manager (lesson 8.4). To check which account your SSH key authenticates as:

Terminal
$ ssh -T git@github.com

Common mistakes

  • A classic token where a fine-grained one would do. Scope is the blast radius.
  • A personal token used by a server. It leaves with you.
  • No expiry, so it is never revoked.
  • Putting a secret in Variables instead of Secrets, where it is readable in the interface.
  • Assuming redaction is protection. A transformed value is not caught.
  • Keeping tokens "in case". Delete; making a new one takes a minute.

Try it yourself

Goal: audit your credentials and replace one with something weaker.

  1. Open Settings → Developer settings → Personal access tokens and list what you have, with scopes and expiry dates.
  2. Delete anything you cannot explain in one sentence.
  3. Create a fine-grained token limited to your practice repository with Contents: Read and write and a ninety-day expiry, and use it to clone over HTTPS.
  4. In the repository, add an Actions secret called DEMO_SECRET, and a workflow step that runs echo "$DEMO_SECRET" from ${{ secrets.DEMO_SECRET }}.
  5. Read the log and explain what you see.

Expected result: the clone works with a token that can reach one repository, and the workflow log shows *** rather than the value.

Show solution

Step 5 shows redaction working and its limit. GitHub replaces the exact secret string wherever it appears in the log, which catches an accidental echo. It cannot catch a value that was encoded or split first, which is why "the log is redacted" is a safety net rather than a policy.

Check yourself

1. Which token should you reach for by default on GitHub?
2. A build server needs to clone one repository and nothing else. What is right?
3. Why do some checks skip on a pull request from a fork?

Key terms

Environment variable Pipeline Repository (repo)