Repository: JoshuaKGoldberg/create-typescript-app (ts)

Issue:
🚀 Feature: Use get-github-auth-token instead of $(gh auth token)
### Bug Report Checklist

- [X] I have pulled the latest `main` branch of the repository.
- [X] I have [searched for related issues](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aissue) and found none that matched my issue.

### Overview

I just published https://github.com/JoshuaKGoldberg/get-github-auth-token, which is a small utility that attempts to find a GitHub auth token from the following places, in order:

1. `process.env.GH_TOKEN`
2. Executing `gh auth token` as a child process

Let's use that as the underlying way to get GitHub auth tokens. This can work as a precursor to #667 -> #1000.

### Additional Info

💖 

Pull request description:
feat: use get-github-auth-token instead of gh auth token
## PR Checklist

- [x] Addresses an existing open issue: fixes #1532
- [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22)
- [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/create-typescript-app/blob/main/.github/CONTRIBUTING.md) were taken

## Overview

Swaps out `gh auth token` with `await getGitHubAuthToken()`. Doesn't fully remove the dependency on `gh`.

💖 

Patch:
diff --git a/package.json b/package.json
index febbbce..4838f9e 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
 		"all-contributors-for-repository": "^0.2.1",
 		"chalk": "^5.3.0",
 		"execa": "^9.0.0",
+		"get-github-auth-token": "^0.1.0",
 		"git-remote-origin-url": "^4.0.0",
 		"git-url-parse": "^14.0.0",
 		"js-yaml": "^4.1.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 009933b..fd11093 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -20,6 +20,9 @@ importers:
       execa:
         specifier: ^9.0.0
         version: 9.1.0
+      get-github-auth-token:
+        specifier: ^0.1.0
+        version: 0.1.0
       git-remote-origin-url:
         specifier: ^4.0.0
         version: 4.0.0
@@ -2366,6 +2369,10 @@ packages:
   get-func-name@2.0.2:
     resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
 
+  get-github-auth-token@0.1.0:
+    resolution: {integrity: sha512-ENm+A39AV0X4+Ls1jiCvmqx+C8hSYTv4d5hV9Ks+EL+gx9a0P9pYYpRE1k2ExwRT3EFQabGXF1Rkdp5FIsLkiw==}
+    engines: {node: '>=18'}
+
   get-intrinsic@1.2.4:
     resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
     engines: {node: '>= 0.4'}
@@ -2441,10 +2448,12 @@ packages:
 
   glob@7.2.3:
     resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+    deprecated: Glob versions prior to v9 are no longer supported
 
   glob@8.1.0:
     resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
     engines: {node: '>=12'}
+    deprecated: Glob versions prior to v9 are no longer supported
 
   global-directory@4.0.1:
     resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==}
@@ -3743,6 +3752,7 @@ packages:
 
   rimraf@3.0.2:
     resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+    deprecated: Rimraf versions prior to v4 are no longer supported
     hasBin: true
 
   rimraf@5.0.7:
@@ -6903,6 +6913,8 @@ snapshots:
 
   get-func-name@2.0.2: {}
 
+  get-github-auth-token@0.1.0: {}
+
   get-intrinsic@1.2.4:
     dependencies:
       es-errors: 1.3.0
diff --git a/src/shared/options/getGitHub.ts b/src/shared/options/getGitHub.ts
index 1333690..2a73795 100644
--- a/src/shared/options/getGitHub.ts
+++ b/src/shared/options/getGitHub.ts
@@ -1,4 +1,4 @@
-import { $ } from "execa";
+import { getGitHubAuthToken } from "get-github-auth-token";
 import { Octokit } from "octokit";
 
 export interface GitHub {
@@ -7,16 +7,15 @@ export interface GitHub {
 }
 
 export async function getGitHub(): Promise<GitHub | undefined> {
-	try {
-		await $`gh auth status`;
-	} catch (error) {
+	const auth = await getGitHubAuthToken();
+
+	if (!auth.succeeded) {
 		throw new Error("GitHub authentication failed.", {
-			cause: (error as Error).message,
+			cause: auth.error,
 		});
 	}
 
-	const auth = (await $`gh auth token`).stdout.trim();
-	const octokit = new Octokit({ auth });
+	const octokit = new Octokit({ auth: auth.token });
 
-	return { auth, octokit };
+	return { auth: auth.token, octokit };
 }
diff --git a/src/steps/uninstallPackages.ts b/src/steps/uninstallPackages.ts
index 68e7ab4..ea22f9c 100644
--- a/src/steps/uninstallPackages.ts
+++ b/src/steps/uninstallPackages.ts
@@ -11,6 +11,7 @@ export async function uninstallPackages(offline: boolean | undefined) {
 			"all-contributors-for-repository",
 			"chalk",
 			"execa",
+			"get-github-auth-token",
 			"git-remote-origin-url",
 			"git-url-parse",
 			"lazy-value",


Test patch:
diff --git a/src/shared/options/getGitHub.test.ts b/src/shared/options/getGitHub.test.ts
index 10dd11c..3cbe3a2 100644
--- a/src/shared/options/getGitHub.test.ts
+++ b/src/shared/options/getGitHub.test.ts
@@ -2,11 +2,11 @@ import { describe, expect, it, vi } from "vitest";
 
 import { getGitHub } from "./getGitHub.js";
 
-const mock$ = vi.fn();
+const mockGetGitHubAuthToken = vi.fn();
 
-vi.mock("execa", () => ({
-	get $() {
-		return mock$;
+vi.mock("get-github-auth-token", () => ({
+	get getGitHubAuthToken() {
+		return mockGetGitHubAuthToken;
 	},
 }));
 
@@ -25,17 +25,24 @@ vi.mock("octokit", () => ({
 }));
 
 describe("getOctokit", () => {
-	it("throws an error when gh auth status fails", async () => {
-		mock$.mockRejectedValueOnce(new Error("Oh no!"));
+	it("throws an error when getGitHubAuthToken fails", async () => {
+		mockGetGitHubAuthToken.mockResolvedValue({
+			error: "Oh no!",
+			succeeded: false,
+		});
 
 		await expect(getGitHub).rejects.toMatchInlineSnapshot(
 			"[Error: GitHub authentication failed.]",
 		);
 	});
 
-	it("returns a new Octokit when gh auth status succeeds", async () => {
+	it("returns a new Octokit when getGitHubAuthToken succeeds", async () => {
 		const auth = "abc123";
-		mock$.mockResolvedValueOnce({}).mockResolvedValueOnce({ stdout: auth });
+
+		mockGetGitHubAuthToken.mockResolvedValue({
+			succeeded: true,
+			token: auth,
+		});
 
 		const actual = await getGitHub();