Chapter 02Lesson 01~105 minutes

Account Security, Two-Factor Authentication, SSH Keys, Tokens, and Credential Hygiene: Concepts, Architecture, and Mental Model

Separate authentication from authorization and learn why browser login, Git transport, API clients, and automation use different credentials with different trust boundaries.

AuthenticationAuthorization2FACredential lifecycle

Learning objectives

  • Separate authentication (proving who or what you are) from authorization (what that identity may do).
  • Distinguish browser sign-in, Git over SSH/HTTPS, GitHub CLI/API authentication, GitHub App credentials, and workflow GITHUB_TOKEN.
  • Explain how 2FA, passkeys, security keys, recovery codes, and recovery planning protect an interactive GitHub account.
  • Describe SSH keys, fine-grained PATs, classic PATs, and GitHub App installation tokens by owner, scope, lifespan, storage, and revocation model.
  • Explain why a valid credential can still be denied by repository permissions, organization policy, SSO authorization, or resource ownership.
  • Build a read-only credential inventory without printing a token, private key, recovery code, or other secret material.
Availability: The mandatory path targets GitHub.com with a personal GitHub Free account and local Git/SSH tooling. Enterprise SAML SSO examples are clearly optional and use documentation/fixtures when the learner does not have enterprise access.

1. The practical problem: one GitHub identity has several authentication doors

Chapter 01 separated local Git state from GitHub-hosted state. Security adds another boundary: signing into github.com in a browser is not the same operation as authenticating a Git push, calling the REST API, or letting a workflow act on a repository. The same human may therefore have several credentials, each with a different purpose and blast radius.

Consider a developer who signs in with a passkey, clones over SSH, runs gh through an OAuth-backed browser login, and maintains an automation integration using a GitHub App. All four paths may ultimately act near the same repository, but GitHub evaluates different credentials and policies on each path. Treating them as “my GitHub password” produces weak designs and confusing failures.

Core model: credential ≠ identity ≠ permission. A credential proves or represents an identity; authorization then evaluates whether that identity may perform the requested operation on the target resource.

2. Authentication versus authorization

Authentication answers “who are you?” or, for automation, “which app/installation/job is making this request?” Authorization answers “may that authenticated principal perform this action on this resource right now?” A credential can authenticate perfectly and still receive 403 Forbidden or 404 Not Found because authorization fails.

Question Authentication layer Authorization layer
Can I sign in to the web UI? Password/social login + 2FA, or passkey, depending on account setup. Repository/org visibility, membership, role, and policy determine what appears after sign-in.
Can I git push over SSH? GitHub maps the presented public key to an account or other supported SSH principal. That account must have permission to update the target repository/ref, and policy may still reject the update.
Can this PAT read a private file? The token must be valid and belong to a user who still has access. The token must target the right resource owner/repository and carry the endpoint permission; org/SSO policy can narrow it further.
Can a workflow call an API? The job receives a GITHUB_TOKEN installation token. Effective permissions are bounded by repository/org defaults, workflow permissions, and event context.

3. Credential map: identify the channel before choosing a secret

Channel Typical credential Where it lives What it should not be confused with
Browser sign-in Password + 2FA, passkey, or enterprise identity flow Browser/device plus GitHub account/IdP state Git commit author email or an SSH private key
Git over SSH SSH private key locally; public key registered with GitHub Private key on device/agent; public half on GitHub A REST API bearer token
Git over HTTPS Credential-manager/OAuth flow, or PAT where appropriate OS credential store or approved secret store Browser session cookie
GitHub CLI Browser/device OAuth flow by default; environment token for headless cases System credential store when available; otherwise gh may fall back to a file GitHub account password
REST/GraphQL API PAT, GitHub App token, OAuth token, or workflow token depending on caller Secret store/memory; never source control SSH key used for Git transport
GitHub Actions Job-specific GITHUB_TOKEN, or another explicitly supplied credential when required Injected into the job; short-lived A general-purpose token for unrelated repositories

The matrix is intentionally redundant with the real world: multiple methods can work. The security question is not “which credential is strongest in the abstract?” It is “which credential proves the intended principal with the least privilege, shortest useful lifetime, smallest storage surface, and clearest revocation path?”

4. Two-factor authentication protects interactive account access

Two-factor authentication (2FA) requires another factor in addition to the primary sign-in secret. GitHub currently supports TOTP authenticator apps and SMS as primary 2FA setup methods, with passkeys, security keys, and GitHub Mobile available as additional methods in supported contexts. GitHub recommends stronger, more reliable methods such as TOTP and security keys over SMS where practical.

A passkey is a WebAuthn credential that can satisfy both password and 2FA requirements for GitHub sign-in. A security key registered as a second factor proves user presence and is used with the password unless registered/used as a passkey. The operational lesson is resilience: configure more than one independent authentication path rather than making one phone the single point of failure.

Do not demonstrate 2FA by disabling it. Inspection and recovery planning are the lab. Changing or removing a real account factor is security-sensitive and is unnecessary for learning.

5. Recovery is part of authentication architecture

Recovery codes are emergency credentials, not screenshots for a runbook. Store them offline or in an approved password/secret manager separate from the device that holds your normal second factor. GitHub also documents other recovery possibilities, including configured passkeys, security keys, verified devices, and in some circumstances previously configured SSH keys or personal access tokens.

The hard boundary matters: GitHub documents that Support cannot restore access to a 2FA-protected account when all configured 2FA credentials and recovery methods are lost. Therefore “we will contact support” is not an account-recovery design. A production team should know who owns important repositories, how ownership survives one person losing an account, and which recovery factors exist before an incident.

Recovery evidence rule: record that recovery material exists and when it was last reviewed. Never record the recovery codes themselves in a ticket, repository, screenshot, lesson note, or chat.

6. SSH keys authenticate Git transport without sending your private key

An SSH key pair contains a private key and a public key. The private key stays under your control; GitHub stores the public key. During SSH authentication, your client proves possession of the private key cryptographically. The private key is not uploaded to GitHub.

For a normal developer key, use a modern key type supported by your OpenSSH version and GitHub. Current GitHub documentation uses Ed25519 by default and recommends a passphrase. The SSH agent can hold unlocked key material so you do not repeatedly type the passphrase. A hardware-backed SSH key can further reduce private-key export risk.

Boundary: the SSH key answers “which GitHub identity is presenting this key?” Repository permissions and branch/ruleset policy still decide whether a fetch or push is authorized.

7. HTTPS authentication: prefer a credential manager over copying tokens

Git over HTTPS does not require you to keep a PAT in a remote URL. GitHub recommends GitHub CLI or Git Credential Manager (GCM) to handle credentials for HTTPS. These tools can use browser-based authentication and store resulting credentials in an operating-system credential store.

This reduces accidental exposure through shell history, process listings, screenshots, and .git/config. It also makes 2FA-compatible authentication practical without asking developers to manually manage a long-lived token for routine Git operations.

Never use https://TOKEN@github.com/OWNER/REPO.git as a teaching shortcut. If a token appears in a remote URL, treat it as exposed: revoke/rotate it first, then replace the URL and inspect shell/history/log surfaces.

8. Personal access tokens: fine-grained first when the scenario supports them

A personal access token (PAT) acts on behalf of the user who created it. It cannot grant powers the user does not already possess. GitHub supports fine-grained PATs and classic PATs. Fine-grained PATs can be restricted to one resource owner, selected repositories, and specific repository/organization/account permissions, so they usually provide a smaller blast radius.

Classic PATs use broader OAuth-style scopes and remain necessary for some scenarios that fine-grained PATs do not yet support. Current GitHub documentation explicitly describes capability gaps for fine-grained PATs, so “fine-grained always works” is incorrect. The safe policy is: use a fine-grained PAT when the documented endpoint/workflow supports it; use a classic PAT only for a documented compatibility requirement; prefer a GitHub App for durable organization automation.

Property Fine-grained PAT Classic PAT
Resource boundary One selected resource owner; can narrow to selected repositories. Scopes can cover broad sets of repositories/resources accessible to the user.
Permission model Fine-grained repository/org/account permissions. Broader scopes such as repo or read:org.
Organization governance Can be subject to approval/policy. Can be restricted/blocked by org or enterprise policy.
Default recommendation Prefer when the required operation is supported. Use only when the documented scenario requires classic-token capability.

9. Automation identities: GitHub App tokens and GITHUB_TOKEN

Long-lived automation should not automatically inherit one engineer’s personal identity. A GitHub App can authenticate as the app, as an installation, or on behalf of a user. For server-side automation, an installation access token is attractive because its permissions are derived from the App installation and it expires after a short period (currently one hour).

Inside GitHub Actions, the built-in GITHUB_TOKEN is itself a GitHub App installation access token created for each job. Its permissions are limited to the workflow repository and further shaped by repository/organization policy, workflow permissions, and event context. Chapters 13–20 cover that execution model deeply; here the point is identity separation: a workflow token is not your personal PAT.

Automation preference: use GITHUB_TOKEN when a workflow only needs its own repository. Use a GitHub App when durable automation needs a distinct, governable installation identity. Reach for a PAT only when the use case genuinely needs a user-bound credential.

10. Credential lifecycle: scope, expiration, rotation, revocation, storage, audit

A credential is a lifecycle, not a string. Before creating one, answer six questions: who owns it, what can it access, how long should it live, where will it be stored, how will activity be attributed, and how will it be revoked? If any answer is “we do not know,” the credential is not production-ready.

Control Question to answer Good operating pattern
Scope Which resource and operation are required? Select only required repositories and read/write permissions.
Expiration How long must this credential exist? Use the shortest practical lifetime; treat “no expiration” as an exception requiring justification.
Rotation How is replacement introduced without outage? Document owner, consumers, cutover, and validation before revoking old material.
Revocation What is the emergency kill path? Owner/admin knows the exact settings/API path and can invalidate it quickly.
Storage Can it leak through source/history/logs? OS credential manager, secret manager, hardware key, or job-scoped injection; never source control.
Auditability Whose action will GitHub record? Prefer dedicated app/workflow identity for automation instead of a shared human PAT.

11. SSO can deny a credential that is otherwise valid

On GitHub Enterprise Cloud organizations that use SAML single sign-on (SSO), a user can have a valid GitHub credential and still be unable to access organization resources until the credential is authorized for that organization. Classic PATs require explicit SSO authorization; fine-grained PAT authorization is integrated into token creation; user SSH keys may also require authorization after the user has a linked external identity.

This is an authorization boundary, not proof that the token/key is “bad.” It also does not apply universally: SSO credential authorization is an Enterprise Cloud concept and GitHub Enterprise Server has a different identity/deployment model. Always read the documentation version that matches the deployment you are operating.

Optional enterprise extension: if you do not have an SSO-enabled organization, use the failure fixture in Lesson 4. Do not create an enterprise or paid organization for this chapter.

12. Read-only inspection first: prove state without exposing secrets

A safe security session starts by identifying which credentials and helpers exist without printing their secret values. The following commands are deliberately inspection-oriented:

gh auth status --active --hostname github.com
gh auth status --json hosts
git remote -v
git config --show-origin --get-all credential.helper
ssh-add -l

gh auth status tests stored authentication state but does not reveal the token unless you explicitly request --show-token. Do not use that flag in this course. ssh-add -l lists fingerprints for keys currently loaded in the SSH agent; it does not print private key contents. git remote -v is also a leak detector: if a credential was embedded in a URL, stop and revoke it before continuing.

CLI nuance: current gh auth status returns exit code 1 when stored accounts have authentication issues. With --json, it normally exits zero unless there is a fatal error, so automation must inspect the JSON state rather than assuming the exit code has identical meaning.

13. The trust flow: credential validation is only one gate

Authentication and authorization are separate gates
flowchart TD
  C[Caller: human / Git / gh / app / workflow] --> K[Credential presented]
  K --> A{Authentication valid?}
  A -- no --> E1[401 / SSH auth failure / login failure]
  A -- yes --> I[Resolved principal]
  I --> P{Resource permission + token scope + policy + SSO?}
  P -- no --> E2[403 / 404 / policy rejection]
  P -- yes --> O[Requested operation]
  O --> V[Audit / verification evidence]

The first decision validates the credential and resolves a principal. The second decision evaluates access to the target resource. GitHub may also apply policy—for example organization PAT policy, SSO requirements, branch/ruleset controls, or workflow token restrictions. This is why “the token works on one repository” does not prove that it should work everywhere.

14. Why this matters in DevOps

Delivery systems amplify credentials. A developer key may be used a few times per hour; an automation token may perform hundreds of API or Git operations without human review. If the credential belongs to a powerful human account, never expires, and is copied into a CI variable, the automation inherits a large and poorly attributable blast radius.

Secure DevOps therefore treats identity as architecture: strong interactive authentication, least-privilege machine identities, short-lived tokens where possible, protected storage, documented rotation/revocation, and independent evidence that the expected principal—not merely “some credential”—performed the operation.

15. Common misconceptions

Misconception Better model
“2FA protects my PAT if it leaks.” 2FA protects interactive sign-in. A bearer token that is valid can usually be used without completing your interactive 2FA ceremony again.
“SSH is more authorized than HTTPS.” SSH and HTTPS are transport/authentication choices. Repository authorization is evaluated separately.
“A token scope grants me admin access.” A token can only narrow the owner’s existing access; it cannot elevate the user beyond their role.
“If ssh -T exits nonzero, SSH is broken.” GitHub’s successful SSH test intentionally exits with code 1 after printing the success banner because shell access is not provided.
“A valid token should work in every organization.” Resource owner, repository selection, fine-grained permission, organization policy, SSO, and user membership can all constrain it.
“Deleting a leaked token from Git history fixes the incident.” Revoke/rotate first. History cleanup reduces future exposure; it does not invalidate a credential already copied by an attacker.

16. Mini lab: create a secret-free authentication inventory

Do this against your normal GitHub account without changing any credential. The goal is to produce evidence about types and state, not values.

  1. Open Settings → Password and authentication. Record only: whether 2FA is enabled, which categories of second-factor/recovery methods exist, and the date you reviewed them. Do not open/copy recovery codes.
  2. Open Settings → SSH and GPG keys. Record the titles and public-key fingerprints shown for authentication keys you recognize. Do not copy private keys.
  3. Open Developer settings → Personal access tokens. Record token names, type, expiration, and broad purpose only. Do not reveal token values.
  4. Run the read-only CLI commands from section 12. Record the active GitHub host/account and configured Git credential helper—not any token.
  5. Write one sentence for each credential answering: “what channel uses this?” and “how would I revoke it?”
Stop condition: if you discover a credential you do not recognize, a token embedded in a remote URL, or a key on a lost device, do not continue the lab mechanically. Preserve the non-secret evidence and follow your account/organization incident process.

17. Verification checklist

  • You can explain authentication and authorization without using them as synonyms.
  • You can identify which credential type is used for browser, SSH Git, HTTPS Git, gh/API, GitHub Apps, and GitHub Actions.
  • Your notes contain no token values, private keys, recovery codes, session cookies, or screenshots containing secrets.
  • You know at least two independent account-recovery paths or have identified a recovery gap to fix outside the lab.
  • You can explain why SSO can reject a valid PAT/SSH key without calling the credential invalid.
  • You know that revocation/rotation comes before repository-history cleanup after a secret leak.

Knowledge check

A fine-grained PAT is valid but returns 404 for a private repository. What should you test before regenerating it with broad permissions?

Does enabling 2FA make a copied bearer token safe?

Why is GITHUB_TOKEN not “the developer’s GitHub token”?

What is the first technical action after confirming a PAT was exposed?

A successful ssh -T git@github.com prints your username but exits 1. Is authentication broken?

18. Summary

GitHub security begins by separating identity channels. Browser login uses interactive account authentication; Git transport uses SSH or HTTPS credentials; API clients use tokens appropriate to the caller; GitHub Apps provide installable automation identities; Actions jobs receive a repository-scoped GITHUB_TOKEN.

Every credential then passes a separate authorization layer: user/app permissions, resource ownership, selected repositories, token permissions/scopes, organization policy, and possibly SSO. Secure operation means least privilege, strong recovery, protected storage, explicit expiration/rotation/revocation, and secret-free evidence.

Next lesson

Turn the model into a disposable authentication workflow

Lesson 02 generates a lab SSH key, verifies its fingerprint and GitHub identity, authenticates GitHub CLI through the browser flow, inspects API identity safely, and removes temporary credentials with proof.

Authoritative references

 About authentication to GitHub
 Configuring two-factor authentication
 Configuring 2FA recovery methods
 Recovering an account after losing 2FA credentials
 Connecting to GitHub with SSH
 Managing personal access tokens
 Authenticating with a GitHub App
 GITHUB_TOKEN
 About authentication with single sign-on
 gh auth login
 gh auth status

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.