From 58f54ce745f52cbcc69eb11dff4080eb1fb4d2f4 Mon Sep 17 00:00:00 2001 From: Justin Paul Date: Tue, 23 Jun 2026 20:32:04 -0400 Subject: [PATCH] Module 8: walk through GitHub PAT setup, link SSH as optional (#106) (#107) Co-authored-by: Justin Paul Co-committed-by: Justin Paul --- modules/08-remotes-and-hosting/README.md | 87 ++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/modules/08-remotes-and-hosting/README.md b/modules/08-remotes-and-hosting/README.md index 24b33d8..0df851f 100644 --- a/modules/08-remotes-and-hosting/README.md +++ b/modules/08-remotes-and-hosting/README.md @@ -323,6 +323,88 @@ WSL, or Git Bash on Windows. Continues the `tasks-app` repo from Module 2. *direct the agent* to do the git work (add the remote, push, clone, fetch, pull) and you verify each result yourself. You don't type the git commands by hand. +### Set up GitHub authentication (do this first) + +This is the one part you do by hand in the web UI, and it's failure mode #1 above: the single most +common first-push wall. Set it up *before* Part A so the push just works. You have two paths; do +**one**. This lab walks the **PAT / HTTPS** path step by step on GitHub as the worked example, +because it's all in the browser and needs no command-line setup. SSH is the optional alternative, +linked below. + +> **Other host?** These are GitHub's exact menu paths as the worked example. On GitLab, Bitbucket, +> Codeberg, or your own Forgejo/Gitea the *shape* is identical (see the "Getting a credential" callout +> in the lesson) but the menu names drift; find your host's "access tokens" or "SSH keys" settings. + +**Path 1: Personal access token (PAT) over HTTPS.** Generate a token in GitHub's web UI, then paste +it once when Git asks for a password. + +1. On GitHub, go to your avatar (top right) → **Settings** → **Developer settings** (bottom of the + left sidebar) → **Personal access tokens**. GitHub offers two token types: + + - **Fine-grained tokens** (recommended): scoped to a single repository, with explicit permissions. + This lab uses fine-grained. + - **Tokens (classic)**: older, broader; access is controlled by a coarse `repo` scope that grants + all your repos at once. + + Pick **Fine-grained tokens** → **Generate new token**. + +2. Fill in the token: + + - **Token name:** anything memorable, e.g. `tasks-app-push`. + - **Expiration:** pick a real expiry (30 to 90 days is fine for the lab). Tokens expire by design; + that's a rotation cost you accept for the convenience. + - **Repository access:** choose **Only select repositories** and select your `tasks-app` repo. If + you haven't created the empty remote yet (Part A step 1), come back and select it after, or + create the repo first and then make the token. The token only needs to *reach* a repo that + exists. + - **Permissions → Repository permissions → Contents:** set it to **Read and write**. This is the + write scope, and it is *the* gotcha: a token without it authenticates fine and then `403`s on + push (failure mode #1's scope trap). GitHub auto-adds **Metadata: Read** when you do this; leave + it. + +3. Click **Generate token** and **copy the value immediately.** GitHub shows it exactly once. If you + lose it, you generate a new one rather than recover the old. + +4. At the first push (Part A step 2), Git prompts for a **username** and **password**: + + - **Username:** your GitHub username. + - **Password:** paste the **token** (not your GitHub account password; password auth over HTTPS + was removed years ago). Most terminals show *nothing* while you paste a secret; that's normal, + not a hang. Press Enter. + + A **credential helper** caches it after the first success (`git config --global credential.helper`, + set to `osxkeychain` on macOS, `manager` on Windows, or `store`/`cache` on Linux), so you paste the + token *once*, not on every push. + + > **Verify-before-publish:** GitHub's menu wording, token-type names, and the **Contents: Read and + > write** permission label drift. Re-confirm the path **Settings → Developer settings → Personal + > access tokens → Fine-grained tokens** and the Contents scope before relying on these exact names. + +**Path 2: SSH key (optional alternative).** A key you add to your account skips passwords entirely. +It's more upfront setup (generate a keypair, load the ssh-agent, paste the *public* key into GitHub), +but then there's no token to scope, expire, or cache. Follow GitHub's official docs, in order: + +- [Generating a new SSH key and adding it to the ssh-agent](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) +- [Adding a new SSH key to your GitHub account](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account) +- [Testing your SSH connection](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection) + +If you go SSH, use the **SSH** URL (`git@github.com:…`) when you create the remote in Part A, not the +HTTPS one. + +**Which should you pick?** + +| | **PAT / HTTPS** | **SSH key** | +|---|---|---| +| **Setup** | Fast, all in the web UI; nothing to install | More upfront: keygen, ssh-agent, add the public key | +| **After setup** | Credential helper caches the token; otherwise re-paste | No prompts ever; nothing to cache | +| **Network** | Port 443; sails through corporate proxies/firewalls | Port 22; sometimes blocked on locked-down networks | +| **Maintenance** | Expires; needs rotation; the write-scope `403` trap; shown once | No expiry by default; no scope to misconfigure | +| **Risk to manage** | A leaked token until it expires/is revoked | A private key + passphrase on your disk | + +Short version: **PAT** is the faster start and the friendlier path behind a corporate firewall; +**SSH** is the lower-friction *long-term* setup once you're past the initial keygen. Either one +satisfies the lab. If you're unsure, do the PAT. + ### Part A: Create the empty remote and push 1. On your host's web UI, create a **new, empty** repository named `tasks-app`. Do **not** add a @@ -514,4 +596,9 @@ tables, and update the "as of" date when you do. - [ ] **Credential/token UI**: the "Getting a credential" callout names menu paths and the write-scope label (`repo` / "read and write") generically; confirm the current wording and scope name on the default-example host before publishing. +- [ ] **GitHub PAT walkthrough** (lab "Set up GitHub authentication"): confirm the menu path + **Settings → Developer settings → Personal access tokens → Fine-grained tokens**, the two token + types (**fine-grained** vs **classic**/`repo`), and that the write scope is **Repository + permissions → Contents: Read and write** (with **Metadata: Read** auto-added). These are + volatile GitHub UI labels; also re-confirm the three linked SSH docs URLs still resolve. - [ ] Update the comparison's **"as of" date** to the build date.