Tokens, SSH keys, security settings
Intermediate GitHub UI
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 → Settings → Developer settings → Personal access tokens → Fine-grained tokens |
| Push and pull over SSH as yourself | SSH key | Settings → SSH and GPG keys |
| Let a server read or write one repository | Deploy key | Repository Settings → Deploy keys |
| Give a workflow a secret | Actions secret | Repository Settings → Secrets and variables → Actions |
| Let an integration act on its own | GitHub App, usually installed rather than built | Organization Settings → GitHub Apps |
| Sign your commits | GPG or SSH signing key | Settings → SSH 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:
- Settings → Developer settings → Personal access tokens: delete what you cannot explain; note what expires soon.
- Settings → SSH and GPG keys: remove keys for machines you no longer have.
- Settings → Sessions and Security log: check where your account has been used.
- Repository Settings → Deploy keys: remove keys for retired systems.
- Repository Settings → Secrets and variables: confirm nothing secret is sitting in Variables.
- 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:
$ git remote -vorigin 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:
$ ssh -T git@github.comThe GitHub extension stores its OAuth token in the operating system keychain; Sign out and back in replaces it. Git over HTTPS uses the credential manager separately, so signing in to VS Code does not fix a rejected push.
Settings → Version Control → GitHub holds the account and its token. An expired one shows as a sign-in prompt in the Pull Requests window.
The same ideas with different names: personal, project and group access tokens, SSH keys, deploy tokens and deploy keys, and CI/CD variables with masked and protected settings. See lesson 9.12.
- Profile photo → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token: choose the owner, the repositories, the permissions and an expiry.
- Settings → SSH and GPG keys → New SSH key for a key, one per machine.
- Repository Settings → Deploy keys for a machine that needs one repository.
- Repository Settings → Secrets and variables → Actions → New repository secret for a workflow secret.
- Settings → Password and authentication for two-factor authentication (lesson 8.5).
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.
- Open Settings → Developer settings → Personal access tokens and list what you have, with scopes and expiry dates.
- Delete anything you cannot explain in one sentence.
- 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.
- In the repository, add an Actions secret called
DEMO_SECRET, and a workflow step that runsecho "$DEMO_SECRET"from${{ secrets.DEMO_SECRET }}. - 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.